Skip to content

Instantly share code, notes, and snippets.

@voxpelli
Last active June 7, 2023 17:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save voxpelli/bee3ed3bc7a6f7580cc894b07f3b2c7f to your computer and use it in GitHub Desktop.
Save voxpelli/bee3ed3bc7a6f7580cc894b07f3b2c7f to your computer and use it in GitHub Desktop.
Highlighted diff of the patch that Apple applies to CrossOver in the Game Porting Toolkit here: https://github.com/apple/homebrew-apple/blob/main/Formula/game-porting-toolkit.rb
This file has been truncated, but you can view the full file.
diff --git a/include/distversion.h b/include/distversion.h
new file mode 100644
index 00000000000..b8a3724b76b
--- /dev/null
+++ wine/include/distversion.h
@@ -0,0 +1,12 @@
+/* ---------------------------------------------------------------
+* distversion.c
+*
+* Copyright 2013, CodeWeavers, Inc.
+*
+* Information from DISTVERSION which needs to find
+* its way into the wine tree.
+* --------------------------------------------------------------- */
+
+#define WINDEBUG_WHAT_HAPPENED_MESSAGE "This can be caused by a problem in the program or a deficiency in Wine. You may want to check <a href=\"http://www.codeweavers.com/compatibility/\">http://www.codeweavers.com/compatibility/</a> for tips about running this application."
+
+#define WINDEBUG_USER_SUGGESTION_MESSAGE "If this problem is not present under Windows and has not been reported yet, you can save the detailed information to a file using the \"Save As\" button, then <a href=\"http://www.codeweavers.com/support/tickets/enter/\">file a bug report</a> and attach that file to the report."
\ No newline at end of file
--
2.39.2 (Apple Git-144)
diff --git a/configure b/configure
index 2d57c7e085d..b9b57c0d509 100755
--- wine/configure
+++ wine/configure
@@ -950,6 +950,7 @@ enable_amstream
enable_apisetschema
enable_apphelp
enable_appwiz_cpl
+enable_api_ms_win_power_base_l1_1_0
enable_atl
enable_atl100
enable_atl110
@@ -21776,6 +21777,7 @@ wine_fn_config_makefile dlls/apisetschema enable_apisetschema
wine_fn_config_makefile dlls/apphelp enable_apphelp
wine_fn_config_makefile dlls/apphelp/tests enable_tests
wine_fn_config_makefile dlls/appwiz.cpl enable_appwiz_cpl
+wine_fn_config_makefile dlls/api-ms-win-power-base-l1-1-0 enable_api_ms_win_power_base_l1_1_0
wine_fn_config_makefile dlls/atl enable_atl
wine_fn_config_makefile dlls/atl/tests enable_tests
wine_fn_config_makefile dlls/atl100 enable_atl100
diff --git a/configure.ac b/configure.ac
diff --git a/configure.ac b/configure.ac
index 50c50d15eda..58063421cce 100644
--- wine/configure.ac
+++ wine/configure.ac
@@ -2424,6 +2424,7 @@ WINE_CONFIG_MAKEFILE(dlls/apisetschema)
WINE_CONFIG_MAKEFILE(dlls/apphelp)
WINE_CONFIG_MAKEFILE(dlls/apphelp/tests)
WINE_CONFIG_MAKEFILE(dlls/appwiz.cpl)
+WINE_CONFIG_MAKEFILE(dlls/api-ms-win-power-base-l1-1-0)
WINE_CONFIG_MAKEFILE(dlls/atl)
WINE_CONFIG_MAKEFILE(dlls/atl/tests)
WINE_CONFIG_MAKEFILE(dlls/atl100)
diff --git a/dlls/api-ms-win-power-base-l1-1-0/Makefile.in b/dlls/api-ms-win-power-base-l1-1-0/Makefile.in
new file mode 100644
index 00000000000..8b26d4be82f
--- /dev/null
+++ wine/dlls/api-ms-win-power-base-l1-1-0/Makefile.in
@@ -0,0 +1 @@
+MODULE = api-ms-win-power-base-l1-1-0.dll
diff --git a/dlls/api-ms-win-power-base-l1-1-0/api-ms-win-power-base-l1-1-0.spec b/dlls/api-ms-win-power-base-l1-1-0/api-ms-win-power-base-l1-1-0.spec
new file mode 100644
index 00000000000..dd056946ac6
--- /dev/null
+++ wine/dlls/api-ms-win-power-base-l1-1-0/api-ms-win-power-base-l1-1-0.spec
@@ -0,0 +1,5 @@
+@ stdcall CallNtPowerInformation(long ptr long ptr long) powrprof.CallNtPowerInformation
+@ stdcall GetPwrCapabilities(ptr) powrprof.GetPwrCapabilities
+@ stdcall PowerDeterminePlatformRoleEx(long) powrprof.PowerDeterminePlatformRoleEx
+@ stdcall PowerRegisterSuspendResumeNotification(long ptr ptr) powrprof.PowerRegisterSuspendResumeNotification
+@ stub PowerUnregisterSuspendResumeNotification
diff --git a/tools/make_specfiles b/tools/make_specfiles
index 3c4c40544b8..cdaf0ccf209 100755
--- wine/tools/make_specfiles
+++ wine/tools/make_specfiles
@@ -139,6 +139,11 @@ my @dll_groups =
"sppc",
"slc",
],
+ [
+ "ntdll",
+ "powrprof",
+ "api-ms-win-power-base-l1-1-0",
+ ]
);
my $update_flags = 0;
--
2.39.2 (Apple Git-144)
diff --git a/configure b/configure
index b9b57c0d509..24f958073a0 100755
--- wine/configure
+++ wine/configure
@@ -950,6 +950,7 @@ enable_amstream
enable_apisetschema
enable_apphelp
enable_appwiz_cpl
+enable_api_ms_win_core_psm_appnotify_l1_1_0
enable_api_ms_win_power_base_l1_1_0
enable_atl
enable_atl100
@@ -21777,6 +21778,7 @@ wine_fn_config_makefile dlls/apisetschema enable_apisetschema
wine_fn_config_makefile dlls/apphelp enable_apphelp
wine_fn_config_makefile dlls/apphelp/tests enable_tests
wine_fn_config_makefile dlls/appwiz.cpl enable_appwiz_cpl
+wine_fn_config_makefile dlls/api-ms-win-core-psm-appnotify-l1-1-0 enable_api_ms_win_core_psm_appnotify_l1_1_0
wine_fn_config_makefile dlls/api-ms-win-power-base-l1-1-0 enable_api_ms_win_power_base_l1_1_0
wine_fn_config_makefile dlls/atl enable_atl
wine_fn_config_makefile dlls/atl/tests enable_tests
diff --git a/dlls/api-ms-win-core-psm-appnotify-l1-1-0/Makefile.in b/dlls/api-ms-win-core-psm-appnotify-l1-1-0/Makefile.in
new file mode 100644
index 00000000000..8a3d2ad98cb
--- /dev/null
+++ wine/dlls/api-ms-win-core-psm-appnotify-l1-1-0/Makefile.in
@@ -0,0 +1 @@
+MODULE = api-ms-win-core-psm-appnotify-l1-1-0.dll
diff --git a/dlls/api-ms-win-core-psm-appnotify-l1-1-0/api-ms-win-core-psm-appnotify-l1-1-0.spec b/dlls/api-ms-win-core-psm-appnotify-l1-1-0/api-ms-win-core-psm-appnotify-l1-1-0.spec
new file mode 100644
index 00000000000..8b069d66e62
--- /dev/null
+++ wine/dlls/api-ms-win-core-psm-appnotify-l1-1-0/api-ms-win-core-psm-appnotify-l1-1-0.spec
@@ -0,0 +1,2 @@
+@ stub RegisterAppStateChangeNotification
+@ stub UnregisterAppStateChangeNotification
--
2.39.2 (Apple Git-144)
diff --git a/dlls/crypt32/base64.c b/dlls/crypt32/base64.c
index 11fb137ed91..b61ed7ff8cc 100644
--- wine/dlls/crypt32/base64.c
+++ wine/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:
@@ -883,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)
@@ -928,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:
@@ -1094,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)
@@ -1139,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/cert.c b/dlls/crypt32/cert.c
index ad39b7d18c7..b57cc685212 100644
--- wine/dlls/crypt32/cert.c
+++ wine/dlls/crypt32/cert.c
@@ -1006,6 +1006,7 @@ BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
CryptMemFree(info);
if (cert_in_store)
CertFreeCertificateContext(cert_in_store);
+ if (ret) SetLastError(0);
return ret;
}
diff --git a/dlls/crypt32/chain.c b/dlls/crypt32/chain.c
index cf244f2ac6c..4a60e9a60ff 100644
--- wine/dlls/crypt32/chain.c
+++ wine/dlls/crypt32/chain.c
@@ -3696,6 +3696,44 @@ static BYTE msPubKey4[] = {
0xa6,0xc6,0x48,0x4c,0xc3,0x37,0x51,0x23,0xd3,0x27,0xd7,0xb8,0x4e,0x70,0x96,
0xf0,0xa1,0x44,0x76,0xaf,0x78,0xcf,0x9a,0xe1,0x66,0x13,0x02,0x03,0x01,0x00,
0x01 };
+/* from Microsoft Root Certificate Authority 2011 */
+static BYTE msPubKey5[] = {
+0x30,0x82,0x02,0x0a,0x02,0x82,0x02,0x01,0x00,0xb2,0x80,0x41,0xaa,0x35,0x38,
+0x4d,0x13,0x72,0x32,0x68,0x22,0x4d,0xb8,0xb2,0xf1,0xff,0xd5,0x52,0xbc,0x6c,
+0xc7,0xf5,0xd2,0x4a,0x8c,0x36,0xee,0xd1,0xc2,0x5c,0x7e,0x8c,0x8a,0xae,0xaf,
+0x13,0x28,0x6f,0xc0,0x73,0xe3,0x3a,0xce,0xd0,0x25,0xa8,0x5a,0x3a,0x6d,0xef,
+0xa8,0xb8,0x59,0xab,0x13,0x23,0x68,0xcd,0x0c,0x29,0x87,0xd1,0x6f,0x80,0x5c,
+0x8f,0x44,0x7f,0x5d,0x90,0x01,0x52,0x58,0xac,0x51,0xc5,0x5f,0x2a,0x87,0xdc,
+0xdc,0xd8,0x0a,0x1d,0xc1,0x03,0xb9,0x7b,0xb0,0x56,0xe8,0xa3,0xde,0x64,0x61,
+0xc2,0x9e,0xf8,0xf3,0x7c,0xb9,0xec,0x0d,0xb5,0x54,0xfe,0x4c,0xb6,0x65,0x4f,
+0x88,0xf0,0x9c,0x48,0x99,0x0c,0x42,0x0b,0x09,0x7c,0x31,0x59,0x17,0x79,0x06,
+0x78,0x28,0x8d,0x89,0x3a,0x4c,0x03,0x25,0xbe,0x71,0x6a,0x5c,0x0b,0xe7,0x84,
+0x60,0xa4,0x99,0x22,0xe3,0xd2,0xaf,0x84,0xa4,0xa7,0xfb,0xd1,0x98,0xed,0x0c,
+0xa9,0xde,0x94,0x89,0xe1,0x0e,0xa0,0xdc,0xc0,0xce,0x99,0x3d,0xea,0x08,0x52,
+0xbb,0x56,0x79,0xe4,0x1f,0x84,0xba,0x1e,0xb8,0xb4,0xc4,0x49,0x5c,0x4f,0x31,
+0x4b,0x87,0xdd,0xdd,0x05,0x67,0x26,0x99,0x80,0xe0,0x71,0x11,0xa3,0xb8,0xa5,
+0x41,0xe2,0xa4,0x53,0xb9,0xf7,0x32,0x29,0x83,0x0c,0x13,0xbf,0x36,0x5e,0x04,
+0xb3,0x4b,0x43,0x47,0x2f,0x6b,0xe2,0x91,0x1e,0xd3,0x98,0x4f,0xdd,0x42,0x07,
+0xc8,0xe8,0x1d,0x12,0xfc,0x99,0xa9,0x6b,0x3e,0x92,0x7e,0xc8,0xd6,0x69,0x3a,
+0xfc,0x64,0xbd,0xb6,0x09,0x9d,0xca,0xfd,0x0c,0x0b,0xa2,0x9b,0x77,0x60,0x4b,
+0x03,0x94,0xa4,0x30,0x69,0x12,0xd6,0x42,0x2d,0xc1,0x41,0x4c,0xca,0xdc,0xaa,
+0xfd,0x8f,0x5b,0x83,0x46,0x9a,0xd9,0xfc,0xb1,0xd1,0xe3,0xb3,0xc9,0x7f,0x48,
+0x7a,0xcd,0x24,0xf0,0x41,0x8f,0x5c,0x74,0xd0,0xac,0xb0,0x10,0x20,0x06,0x49,
+0xb7,0xc7,0x2d,0x21,0xc8,0x57,0xe3,0xd0,0x86,0xf3,0x03,0x68,0xfb,0xd0,0xce,
+0x71,0xc1,0x89,0x99,0x4a,0x64,0x01,0x6c,0xfd,0xec,0x30,0x91,0xcf,0x41,0x3c,
+0x92,0xc7,0xe5,0xba,0x86,0x1d,0x61,0x84,0xc7,0x5f,0x83,0x39,0x62,0xae,0xb4,
+0x92,0x2f,0x47,0xf3,0x0b,0xf8,0x55,0xeb,0xa0,0x1f,0x59,0xd0,0xbb,0x74,0x9b,
+0x1e,0xd0,0x76,0xe6,0xf2,0xe9,0x06,0xd7,0x10,0xe8,0xfa,0x64,0xde,0x69,0xc6,
+0x35,0x96,0x88,0x02,0xf0,0x46,0xb8,0x3f,0x27,0x99,0x6f,0xcb,0x71,0x89,0x29,
+0x35,0xf7,0x48,0x16,0x02,0x35,0x8f,0xd5,0x79,0x7c,0x4d,0x02,0xcf,0x5f,0xeb,
+0x8a,0x83,0x4f,0x45,0x71,0x88,0xf9,0xa9,0x0d,0x4e,0x72,0xe9,0xc2,0x9c,0x07,
+0xcf,0x49,0x1b,0x4e,0x04,0x0e,0x63,0x51,0x8c,0x5e,0xd8,0x00,0xc1,0x55,0x2c,
+0xb6,0xc6,0xe0,0xc2,0x65,0x4e,0xc9,0x34,0x39,0xf5,0x9c,0xb3,0xc4,0x7e,0xe8,
+0x61,0x6e,0x13,0x5f,0x15,0xc4,0x5f,0xd9,0x7e,0xed,0x1d,0xce,0xee,0x44,0xec,
+0xcb,0x2e,0x86,0xb1,0xec,0x38,0xf6,0x70,0xed,0xab,0x5c,0x13,0xc1,0xd9,0x0f,
+0x0d,0xc7,0x80,0xb2,0x55,0xed,0x34,0xf7,0xac,0x9b,0xe4,0xc3,0xda,0xe7,0x47,
+0x3c,0xa6,0xb5,0x8f,0x31,0xdf,0xc5,0x4b,0xaf,0xeb,0xf1,0x02,0x03,0x01,0x00,
+0x01 };
static BOOL WINAPI verify_ms_root_policy(LPCSTR szPolicyOID,
PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
@@ -3705,21 +3743,38 @@ static BOOL WINAPI verify_ms_root_policy(LPCSTR szPolicyOID,
CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } };
DWORD i;
- CRYPT_DATA_BLOB keyBlobs[] = {
+ static const CRYPT_DATA_BLOB keyBlobs[] = {
{ sizeof(msPubKey1), msPubKey1 },
{ sizeof(msPubKey2), msPubKey2 },
{ sizeof(msPubKey3), msPubKey3 },
{ sizeof(msPubKey4), msPubKey4 },
};
+ static const CRYPT_DATA_BLOB keyBlobs_approot[] = {
+ { sizeof(msPubKey5), msPubKey5 },
+ };
PCERT_SIMPLE_CHAIN rootChain =
pChainContext->rgpChain[pChainContext->cChain - 1];
PCCERT_CONTEXT root =
rootChain->rgpElement[rootChain->cElement - 1]->pCertContext;
- for (i = 0; !isMSRoot && i < ARRAY_SIZE(keyBlobs); i++)
+ const CRYPT_DATA_BLOB *keys;
+ unsigned int key_count;
+
+ if (pPolicyPara && pPolicyPara->dwFlags & MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG)
+ {
+ keys = keyBlobs_approot;
+ key_count = ARRAY_SIZE(keyBlobs_approot);
+ }
+ else
+ {
+ keys = keyBlobs;
+ key_count = ARRAY_SIZE(keyBlobs);
+ }
+
+ for (i = 0; !isMSRoot && i < key_count; i++)
{
- msPubKey.PublicKey.cbData = keyBlobs[i].cbData;
- msPubKey.PublicKey.pbData = keyBlobs[i].pbData;
+ msPubKey.PublicKey.cbData = keys[i].cbData;
+ msPubKey.PublicKey.pbData = keys[i].pbData;
if (CertComparePublicKeyInfo(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
&root->pCertInfo->SubjectPublicKeyInfo, &msPubKey)) isMSRoot = TRUE;
}
diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c
index 762d1b54661..19643194b49 100644
--- wine/dlls/crypt32/decode.c
+++ wine/dlls/crypt32/decode.c
@@ -3874,7 +3874,7 @@ static BOOL WINAPI CRYPT_AsnDecodeCertPolicyConstraints(
struct DECODED_RSA_PUB_KEY
{
- DWORD pubexp;
+ CRYPT_INTEGER_BLOB pubexp;
CRYPT_INTEGER_BLOB modulus;
};
@@ -3893,12 +3893,23 @@ static BOOL CRYPT_raw_decode_rsa_pub_key(struct DECODED_RSA_PUB_KEY **decodedKey
FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData),
0 },
{ ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
- CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 },
+ CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB),
+ FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, pubexp.pbData),
+ 0 },
};
ret = CRYPT_AsnDecodeSequence(items, ARRAY_SIZE(items),
pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, decodedKey,
size, NULL, NULL);
+
+ if (ret && (*decodedKey)->pubexp.cbData > sizeof(DWORD))
+ {
+ WARN("Unexpected exponent length %lu.\n", (*decodedKey)->pubexp.cbData);
+ LocalFree(*decodedKey);
+ SetLastError(CRYPT_E_ASN1_LARGE);
+ ret = FALSE;
+ }
+
return ret;
}
@@ -3920,7 +3931,7 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey_Bcrypt(DWORD dwCertEncodingType,
if (ret)
{
/* Header, exponent, and modulus */
- DWORD bytesNeeded = sizeof(BCRYPT_RSAKEY_BLOB) + sizeof(DWORD) +
+ DWORD bytesNeeded = sizeof(BCRYPT_RSAKEY_BLOB) + decodedKey->pubexp.cbData +
decodedKey->modulus.cbData;
if (!pvStructInfo)
@@ -3939,7 +3950,7 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey_Bcrypt(DWORD dwCertEncodingType,
hdr = pvStructInfo;
hdr->Magic = BCRYPT_RSAPUBLIC_MAGIC;
hdr->BitLength = decodedKey->modulus.cbData * 8;
- hdr->cbPublicExp = sizeof(DWORD);
+ hdr->cbPublicExp = decodedKey->pubexp.cbData;
hdr->cbModulus = decodedKey->modulus.cbData;
hdr->cbPrime1 = 0;
hdr->cbPrime2 = 0;
@@ -3947,9 +3958,9 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey_Bcrypt(DWORD dwCertEncodingType,
* in big-endian format, so we need to convert from little-endian
*/
CRYPT_CopyReversed((BYTE *)pvStructInfo + sizeof(BCRYPT_RSAKEY_BLOB),
- (BYTE *)&decodedKey->pubexp, sizeof(DWORD));
+ decodedKey->pubexp.pbData, hdr->cbPublicExp);
CRYPT_CopyReversed((BYTE *)pvStructInfo + sizeof(BCRYPT_RSAKEY_BLOB) +
- sizeof(DWORD), decodedKey->modulus.pbData,
+ hdr->cbPublicExp, decodedKey->modulus.pbData,
decodedKey->modulus.cbData);
}
LocalFree(decodedKey);
@@ -3984,13 +3995,13 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
if (!pvStructInfo)
{
*pcbStructInfo = bytesNeeded;
- ret = TRUE;
}
else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
pvStructInfo, pcbStructInfo, bytesNeeded)))
{
BLOBHEADER *hdr;
RSAPUBKEY *rsaPubKey;
+ unsigned int i;
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
pvStructInfo = *(BYTE **)pvStructInfo;
@@ -4002,7 +4013,11 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo +
sizeof(BLOBHEADER));
rsaPubKey->magic = RSA1_MAGIC;
- rsaPubKey->pubexp = decodedKey->pubexp;
+ rsaPubKey->pubexp = 0;
+ assert(decodedKey->pubexp.cbData <= sizeof(rsaPubKey->pubexp));
+ for (i = 0; i < decodedKey->pubexp.cbData; ++i)
+ rsaPubKey->pubexp |= decodedKey->pubexp.pbData[i] << (i * 8);
+
rsaPubKey->bitlen = decodedKey->modulus.cbData * 8;
memcpy((BYTE *)pvStructInfo + sizeof(BLOBHEADER) +
sizeof(RSAPUBKEY), decodedKey->modulus.pbData,
@@ -6351,6 +6366,112 @@ static BOOL CRYPT_AsnDecodeOCSPNextUpdate(const BYTE *pbEncoded,
return ret;
}
+static BOOL CRYPT_AsnDecodeCertStatus(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BOOL ret = TRUE;
+ BYTE tag = pbEncoded[0] & ~3, status = pbEncoded[0] & 3;
+ DWORD bytesNeeded = FIELD_OFFSET(OCSP_BASIC_RESPONSE_ENTRY, ThisUpdate) -
+ FIELD_OFFSET(OCSP_BASIC_RESPONSE_ENTRY, dwCertStatus);
+
+ if (!cbEncoded)
+ {
+ SetLastError(CRYPT_E_ASN1_EOD);
+ return FALSE;
+ }
+
+ switch (status)
+ {
+ case 0:
+ if (tag != ASN_CONTEXT)
+ {
+ WARN("Unexpected tag %02x\n", tag);
+ SetLastError(CRYPT_E_ASN1_BADTAG);
+ return FALSE;
+ }
+ if (cbEncoded < 2 || pbEncoded[1])
+ {
+ SetLastError(CRYPT_E_ASN1_CORRUPT);
+ return FALSE;
+ }
+ if (!pvStructInfo)
+ *pcbStructInfo = bytesNeeded;
+ else if (*pcbStructInfo < bytesNeeded)
+ {
+ *pcbStructInfo = bytesNeeded;
+ SetLastError(ERROR_MORE_DATA);
+ return FALSE;
+ }
+ if (pvStructInfo)
+ {
+ *(DWORD *)pvStructInfo = 0;
+ *(OCSP_BASIC_REVOKED_INFO **)((char *)pvStructInfo
+ + FIELD_OFFSET(OCSP_BASIC_RESPONSE_ENTRY, u.pRevokedInfo)
+ - FIELD_OFFSET(OCSP_BASIC_RESPONSE_ENTRY, dwCertStatus)) = NULL;
+ }
+ *pcbStructInfo = bytesNeeded;
+ *pcbDecoded = 2;
+ break;
+
+ case 1:
+ {
+ DWORD dataLen;
+
+ if (tag != (ASN_CONTEXT | ASN_CONSTRUCTOR))
+ {
+ WARN("Unexpected tag %02x\n", tag);
+ SetLastError(CRYPT_E_ASN1_BADTAG);
+ return FALSE;
+ }
+ if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+ {
+ BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+ DWORD bytesDecoded, size;
+ FILETIME date;
+
+ if (dataLen)
+ {
+ size = sizeof(date);
+ ret = CRYPT_AsnDecodeGeneralizedTime(pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes,
+ dwFlags, &date, &size, &bytesDecoded);
+ if (ret)
+ {
+ OCSP_BASIC_REVOKED_INFO *info;
+
+ bytesNeeded += sizeof(*info);
+ if (!pvStructInfo)
+ *pcbStructInfo = bytesNeeded;
+ else if (*pcbStructInfo < bytesNeeded)
+ {
+ *pcbStructInfo = bytesNeeded;
+ SetLastError(ERROR_MORE_DATA);
+ return FALSE;
+ }
+ if (pvStructInfo)
+ {
+ *(DWORD *)pvStructInfo = 1;
+ info = *(OCSP_BASIC_REVOKED_INFO **)((char *)pvStructInfo
+ + FIELD_OFFSET(OCSP_BASIC_RESPONSE_ENTRY, u.pRevokedInfo)
+ - FIELD_OFFSET(OCSP_BASIC_RESPONSE_ENTRY, dwCertStatus));
+ info->RevocationDate = date;
+ }
+ *pcbStructInfo = bytesNeeded;
+ *pcbDecoded = 1 + lenBytes + bytesDecoded;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ FIXME("Unhandled status %u\n", status);
+ SetLastError(CRYPT_E_ASN1_BADTAG);
+ return FALSE;
+ }
+
+ return ret;
+}
+
static BOOL CRYPT_AsnDecodeOCSPBasicResponseEntry(const BYTE *pbEncoded, DWORD cbEncoded,
DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
{
@@ -6367,10 +6488,9 @@ static BOOL CRYPT_AsnDecodeOCSPBasicResponseEntry(const BYTE *pbEncoded, DWORD c
{ ASN_INTEGER, offsetof(OCSP_BASIC_RESPONSE_ENTRY, CertId.SerialNumber),
CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE,
offsetof(OCSP_BASIC_RESPONSE_ENTRY, CertId.SerialNumber.pbData), 0 },
- { ASN_CONTEXT, offsetof(OCSP_BASIC_RESPONSE_ENTRY, dwCertStatus),
- CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE,
- 0, 0 },
- /* FIXME: pRevokedInfo */
+ { 0, offsetof(OCSP_BASIC_RESPONSE_ENTRY, dwCertStatus),
+ CRYPT_AsnDecodeCertStatus, sizeof(DWORD), FALSE, TRUE,
+ offsetof(OCSP_BASIC_RESPONSE_ENTRY, u.pRevokedInfo), 0 },
{ ASN_GENERALTIME, offsetof(OCSP_BASIC_RESPONSE_ENTRY, ThisUpdate),
CRYPT_AsnDecodeGeneralizedTime, sizeof(FILETIME), FALSE, FALSE,
0, 0 },
@@ -6401,13 +6521,13 @@ static BOOL CRYPT_AsnDecodeOCSPBasicResponseEntriesArray(const BYTE *pbEncoded,
dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
}
-static BOOL CRYPT_AsnDecodeResponderID(const BYTE *pbEncoded,
+static BOOL CRYPT_AsnDecodeResponderIDByName(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
{
OCSP_BASIC_RESPONSE_INFO *info = pvStructInfo;
- BYTE tag = pbEncoded[0] & ~3, choice = pbEncoded[0] & 3;
- DWORD decodedLen, dataLen, lenBytes, bytesNeeded = sizeof(*info), len;
+ DWORD dataLen, decodedLen, lenBytes, bytesNeeded = sizeof(*info);
+ BYTE tag = pbEncoded[0] & ~3;
CERT_NAME_BLOB *blob;
if (tag != (ASN_CONTEXT | ASN_CONSTRUCTOR))
@@ -6416,15 +6536,78 @@ static BOOL CRYPT_AsnDecodeResponderID(const BYTE *pbEncoded,
SetLastError(CRYPT_E_ASN1_BADTAG);
return FALSE;
}
- if (choice > 2)
+
+ if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
+ return FALSE;
+ lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+ cbEncoded -= 1 + lenBytes;
+
+ if (dataLen > cbEncoded)
{
- WARN("Unexpected choice %02x\n", choice);
- SetLastError(CRYPT_E_ASN1_CORRUPT);
+ SetLastError(CRYPT_E_ASN1_EOD);
+ return FALSE;
+ }
+ pbEncoded += 1 + lenBytes;
+ decodedLen = 1 + lenBytes + dataLen;
+
+ if (pbEncoded[0] != ASN_SEQUENCE)
+ {
+ WARN("Unexpected tag %02x %02x\n", pbEncoded[0], pbEncoded[1]);
+ SetLastError(CRYPT_E_ASN1_BADTAG);
return FALSE;
}
+ if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) bytesNeeded += dataLen;
if (pvStructInfo && *pcbStructInfo >= bytesNeeded)
- info->dwResponderIdChoice = choice;
+ {
+ info->dwResponderIdChoice = 1;
+
+ blob = &info->u.ByNameResponderId;
+ blob->cbData = dataLen;
+ if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
+ blob->pbData = (BYTE *)pbEncoded;
+ else if (blob->cbData)
+ {
+ blob->pbData = (BYTE *)(info + 1);
+ memcpy(blob->pbData, pbEncoded, blob->cbData);
+ }
+ }
+
+ if (pcbDecoded)
+ *pcbDecoded = decodedLen;
+
+ if (!pvStructInfo)
+ {
+ *pcbStructInfo = bytesNeeded;
+ return TRUE;
+ }
+
+ if (*pcbStructInfo < bytesNeeded)
+ {
+ SetLastError(ERROR_MORE_DATA);
+ *pcbStructInfo = bytesNeeded;
+ return FALSE;
+ }
+
+ *pcbStructInfo = bytesNeeded;
+ return TRUE;
+}
+
+static BOOL CRYPT_AsnDecodeResponderIDByKey(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ OCSP_BASIC_RESPONSE_INFO *info = pvStructInfo;
+ DWORD dataLen, decodedLen, lenBytes, bytesNeeded = sizeof(*info), len;
+ BYTE tag = pbEncoded[0] & ~3;
+ CRYPT_HASH_BLOB *blob;
+
+ if (tag != (ASN_CONTEXT | ASN_CONSTRUCTOR))
+ {
+ WARN("Unexpected tag %02x\n", tag);
+ SetLastError(CRYPT_E_ASN1_BADTAG);
+ return FALSE;
+ }
if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
return FALSE;
@@ -6461,7 +6644,8 @@ static BOOL CRYPT_AsnDecodeResponderID(const BYTE *pbEncoded,
if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) bytesNeeded += len;
if (pvStructInfo && *pcbStructInfo >= bytesNeeded)
{
- blob = &info->u.ByNameResponderId;
+ info->dwResponderIdChoice = 2;
+ blob = &info->u.ByKeyResponderId;
blob->cbData = len;
if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
blob->pbData = (BYTE *)pbEncoded;
@@ -6492,6 +6676,28 @@ static BOOL CRYPT_AsnDecodeResponderID(const BYTE *pbEncoded,
return TRUE;
}
+static BOOL CRYPT_AsnDecodeResponderID(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+ BYTE choice = pbEncoded[0] & 3;
+
+ TRACE("choice %02x\n", choice);
+ switch (choice)
+ {
+ case 1:
+ return CRYPT_AsnDecodeResponderIDByName(pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, pcbStructInfo, pcbDecoded);
+ case 2:
+ return CRYPT_AsnDecodeResponderIDByKey(pbEncoded, cbEncoded, dwFlags,
+ pvStructInfo, pcbStructInfo, pcbDecoded);
+ default:
+ WARN("Unexpected choice %02x\n", choice);
+ SetLastError(CRYPT_E_ASN1_CORRUPT);
+ return FALSE;
+ }
+}
+
static BOOL WINAPI CRYPT_AsnDecodeOCSPBasicResponse(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
CRYPT_DECODE_PARA *pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c
index 8086ad2fc0a..8968eb9f15a 100644
--- wine/dlls/crypt32/encode.c
+++ wine/dlls/crypt32/encode.c
@@ -4500,7 +4500,7 @@ static BOOL WINAPI CRYPT_AsnEncodeCertId(DWORD dwCertEncodingType,
return ret;
}
-static BOOL WINAPI CRYPT_AsnEncodeOCSPRequestEntry(DWORD dwCertEncodingType,
+static BOOL CRYPT_AsnEncodeOCSPRequestEntry(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
{
diff --git a/dlls/crypt32/object.c b/dlls/crypt32/object.c
index 8123ed73351..4440c9e0498 100644
--- wine/dlls/crypt32/object.c
+++ wine/dlls/crypt32/object.c
@@ -643,7 +643,7 @@ static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
}
file = CreateFileW(temp_name, GENERIC_READ | GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
- if (file == INVALID_HANDLE_VALUE)
+ if (!file)
{
ERR("Could not create temp file.\n");
SetLastError(ERROR_OUTOFMEMORY);
diff --git a/dlls/crypt32/str.c b/dlls/crypt32/str.c
index 277aeb70d4a..d74df308e4a 100644
--- wine/dlls/crypt32/str.c
+++ wine/dlls/crypt32/str.c
@@ -29,77 +29,45 @@
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
-DWORD WINAPI CertRDNValueToStrA(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
- LPSTR psz, DWORD csz)
+DWORD WINAPI CertRDNValueToStrA(DWORD type, PCERT_RDN_VALUE_BLOB value_blob,
+ LPSTR value, DWORD value_len)
{
- DWORD ret = 0, len;
+ DWORD len, len_mb, ret;
+ LPWSTR valueW;
- TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz);
+ TRACE("(%ld, %p, %p, %ld)\n", type, value_blob, value, value_len);
- switch (dwValueType)
- {
- case CERT_RDN_ANY_TYPE:
- break;
- case CERT_RDN_NUMERIC_STRING:
- case CERT_RDN_PRINTABLE_STRING:
- case CERT_RDN_TELETEX_STRING:
- case CERT_RDN_VIDEOTEX_STRING:
- case CERT_RDN_IA5_STRING:
- case CERT_RDN_GRAPHIC_STRING:
- case CERT_RDN_VISIBLE_STRING:
- case CERT_RDN_GENERAL_STRING:
- len = pValue->cbData;
- if (!psz || !csz)
- ret = len;
- else
- {
- DWORD chars = min(len, csz - 1);
+ len = CertRDNValueToStrW(type, value_blob, NULL, 0);
- if (chars)
- {
- memcpy(psz, pValue->pbData, chars);
- ret += chars;
- csz -= chars;
- }
- }
- break;
- case CERT_RDN_BMP_STRING:
- case CERT_RDN_UTF8_STRING:
- len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pValue->pbData,
- pValue->cbData / sizeof(WCHAR), NULL, 0, NULL, NULL);
- if (!psz || !csz)
- ret = len;
- else
- {
- DWORD chars = min(pValue->cbData / sizeof(WCHAR), csz - 1);
+ if (!(valueW = CryptMemAlloc(len * sizeof(*valueW))))
+ {
+ ERR("No memory.\n");
+ if (value && value_len) *value = 0;
+ return 1;
+ }
- if (chars)
- {
- ret = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pValue->pbData,
- chars, psz, csz - 1, NULL, NULL);
- csz -= ret;
- }
- }
- break;
- default:
- FIXME("string type %ld unimplemented\n", dwValueType);
+ len = CertRDNValueToStrW(type, value_blob, valueW, len);
+ len_mb = WideCharToMultiByte(CP_ACP, 0, valueW, len, NULL, 0, NULL, NULL);
+ if (!value || !value_len)
+ {
+ CryptMemFree(valueW);
+ return len_mb;
}
- if (psz && csz)
+
+ ret = WideCharToMultiByte(CP_ACP, 0, valueW, len, value, value_len, NULL, NULL);
+ if (ret < len_mb)
{
- *(psz + ret) = '\0';
- csz--;
- ret++;
+ value[0] = 0;
+ ret = 1;
}
- else
- ret++;
- TRACE("returning %ld (%s)\n", ret, debugstr_a(psz));
+ CryptMemFree(valueW);
return ret;
}
-DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
- LPWSTR psz, DWORD csz)
+static DWORD rdn_value_to_strW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
+ LPWSTR psz, DWORD csz, BOOL partial_copy)
{
- DWORD ret = 0, len, i, strLen;
+ DWORD ret = 0, len, i;
TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz);
@@ -116,44 +84,42 @@ DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
case CERT_RDN_VISIBLE_STRING:
case CERT_RDN_GENERAL_STRING:
len = pValue->cbData;
- if (!psz || !csz)
- ret = len;
- else
+ if (!psz || !csz) ret = len;
+ else if (len < csz || partial_copy)
{
- WCHAR *ptr = psz;
-
- for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++)
- *ptr = pValue->pbData[i];
- ret = ptr - psz;
+ len = min(len, csz - 1);
+ for (i = 0; i < len; ++i)
+ psz[i] = pValue->pbData[i];
+ ret = len;
}
break;
case CERT_RDN_BMP_STRING:
case CERT_RDN_UTF8_STRING:
- strLen = len = pValue->cbData / sizeof(WCHAR);
+ len = pValue->cbData / sizeof(WCHAR);
if (!psz || !csz)
ret = len;
- else
+ else if (len < csz || partial_copy)
{
WCHAR *ptr = psz;
- for (i = 0; i < strLen && ptr - psz < csz; ptr++, i++)
- *ptr = ((LPCWSTR)pValue->pbData)[i];
- ret = ptr - psz;
+ len = min(len, csz - 1);
+ for (i = 0; i < len; ++i)
+ ptr[i] = ((LPCWSTR)pValue->pbData)[i];
+ ret = len;
}
break;
default:
FIXME("string type %ld unimplemented\n", dwValueType);
}
- if (psz && csz)
- {
- *(psz + ret) = '\0';
- csz--;
- ret++;
- }
- else
- ret++;
- TRACE("returning %ld (%s)\n", ret, debugstr_w(psz));
- return ret;
+ if (psz && csz) psz[ret] = 0;
+ TRACE("returning %ld (%s)\n", ret + 1, debugstr_w(psz));
+ return ret + 1;
+}
+
+DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
+ LPWSTR psz, DWORD csz)
+{
+ return rdn_value_to_strW(dwValueType, pValue, psz, csz, FALSE);
}
static inline BOOL is_quotable_char(WCHAR c)
@@ -175,115 +141,6 @@ static inline BOOL is_quotable_char(WCHAR c)
}
}
-static DWORD quote_rdn_value_to_str_a(DWORD dwValueType,
- PCERT_RDN_VALUE_BLOB pValue, LPSTR psz, DWORD csz)
-{
- DWORD ret = 0, len, i;
- BOOL needsQuotes = FALSE;
-
- TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz);
-
- switch (dwValueType)
- {
- case CERT_RDN_ANY_TYPE:
- break;
- case CERT_RDN_NUMERIC_STRING:
- case CERT_RDN_PRINTABLE_STRING:
- case CERT_RDN_TELETEX_STRING:
- case CERT_RDN_VIDEOTEX_STRING:
- case CERT_RDN_IA5_STRING:
- case CERT_RDN_GRAPHIC_STRING:
- case CERT_RDN_VISIBLE_STRING:
- case CERT_RDN_GENERAL_STRING:
- len = pValue->cbData;
- if (pValue->cbData && isspace(pValue->pbData[0]))
- needsQuotes = TRUE;
- if (pValue->cbData && isspace(pValue->pbData[pValue->cbData - 1]))
- needsQuotes = TRUE;
- for (i = 0; i < pValue->cbData; i++)
- {
- if (is_quotable_char(pValue->pbData[i]))
- needsQuotes = TRUE;
- if (pValue->pbData[i] == '"')
- len += 1;
- }
- if (needsQuotes)
- len += 2;
- if (!psz || !csz)
- ret = len;
- else
- {
- char *ptr = psz;
-
- if (needsQuotes)
- *ptr++ = '"';
- for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++)
- {
- *ptr = pValue->pbData[i];
- if (pValue->pbData[i] == '"' && ptr - psz < csz - 1)
- *(++ptr) = '"';
- }
- if (needsQuotes && ptr - psz < csz)
- *ptr++ = '"';
- ret = ptr - psz;
- }
- break;
- case CERT_RDN_BMP_STRING:
- case CERT_RDN_UTF8_STRING:
- len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pValue->pbData,
- pValue->cbData / sizeof(WCHAR), NULL, 0, NULL, NULL);
- if (pValue->cbData && iswspace(((LPCWSTR)pValue->pbData)[0]))
- needsQuotes = TRUE;
- if (pValue->cbData &&
- iswspace(((LPCWSTR)pValue->pbData)[pValue->cbData / sizeof(WCHAR)-1]))
- needsQuotes = TRUE;
- for (i = 0; i < pValue->cbData / sizeof(WCHAR); i++)
- {
- if (is_quotable_char(((LPCWSTR)pValue->pbData)[i]))
- needsQuotes = TRUE;
- if (((LPCWSTR)pValue->pbData)[i] == '"')
- len += 1;
- }
- if (needsQuotes)
- len += 2;
- if (!psz || !csz)
- ret = len;
- else
- {
- char *dst = psz;
-
- if (needsQuotes)
- *dst++ = '"';
- for (i = 0; i < pValue->cbData / sizeof(WCHAR) &&
- dst - psz < csz; dst++, i++)
- {
- LPCWSTR src = (LPCWSTR)pValue->pbData + i;
-
- WideCharToMultiByte(CP_ACP, 0, src, 1, dst,
- csz - (dst - psz) - 1, NULL, NULL);
- if (*src == '"' && dst - psz < csz - 1)
- *(++dst) = '"';
- }
- if (needsQuotes && dst - psz < csz)
- *dst++ = '"';
- ret = dst - psz;
- }
- break;
- default:
- FIXME("string type %ld unimplemented\n", dwValueType);
- }
- if (psz && csz)
- {
- *(psz + ret) = '\0';
- csz--;
- ret++;
- }
- else
- ret++;
- TRACE("returning %ld (%s)\n", ret, debugstr_a(psz));
- return ret;
-}
-
static DWORD quote_rdn_value_to_str_w(DWORD dwValueType,
PCERT_RDN_VALUE_BLOB pValue, LPWSTR psz, DWORD csz)
{
@@ -375,148 +232,41 @@ static DWORD quote_rdn_value_to_str_w(DWORD dwValueType,
default:
FIXME("string type %ld unimplemented\n", dwValueType);
}
- if (psz && csz)
- {
- *(psz + ret) = '\0';
- csz--;
- ret++;
- }
- else
- ret++;
TRACE("returning %ld (%s)\n", ret, debugstr_w(psz));
return ret;
}
-/* Adds the prefix prefix to the string pointed to by psz, followed by the
- * character '='. Copies no more than csz characters. Returns the number of
- * characters copied. If psz is NULL, returns the number of characters that
- * would be copied.
- */
-static DWORD CRYPT_AddPrefixA(LPCSTR prefix, LPSTR psz, DWORD csz)
+DWORD WINAPI CertNameToStrA(DWORD encoding_type, PCERT_NAME_BLOB name_blob, DWORD str_type, LPSTR str, DWORD str_len)
{
- DWORD chars;
+ DWORD len, len_mb, ret;
+ LPWSTR strW;
- TRACE("(%s, %p, %ld)\n", debugstr_a(prefix), psz, csz);
+ TRACE("(%ld, %p, %08lx, %p, %ld)\n", encoding_type, name_blob, str_type, str, str_len);
- if (psz)
+ len = CertNameToStrW(encoding_type, name_blob, str_type, NULL, 0);
+
+ if (!(strW = CryptMemAlloc(len * sizeof(*strW))))
{
- chars = min(strlen(prefix), csz);
- memcpy(psz, prefix, chars);
- *(psz + chars) = '=';
- chars++;
+ ERR("No memory.\n");
+ if (str && str_len) *str = 0;
+ return 1;
}
- else
- chars = lstrlenA(prefix) + 1;
- return chars;
-}
-DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
- DWORD dwStrType, LPSTR psz, DWORD csz)
-{
- static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
- CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
- static const char commaSep[] = ", ";
- static const char semiSep[] = "; ";
- static const char crlfSep[] = "\r\n";
- static const char plusSep[] = " + ";
- static const char spaceSep[] = " ";
- DWORD ret = 0, bytes = 0;
- BOOL bRet;
- CERT_NAME_INFO *info;
-
- TRACE("(%ld, %p, %08lx, %p, %ld)\n", dwCertEncodingType, pName, dwStrType,
- psz, csz);
- if (dwStrType & unsupportedFlags)
- FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags);
-
- bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
- pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
- if (bRet)
+ len = CertNameToStrW(encoding_type, name_blob, str_type, strW, len);
+ len_mb = WideCharToMultiByte(CP_ACP, 0, strW, len, NULL, 0, NULL, NULL);
+ if (!str || !str_len)
{
- DWORD i, j, sepLen, rdnSepLen;
- LPCSTR sep, rdnSep;
- BOOL reverse = dwStrType & CERT_NAME_STR_REVERSE_FLAG;
- const CERT_RDN *rdn = info->rgRDN;
-
- if(reverse && info->cRDN > 1) rdn += (info->cRDN - 1);
-
- if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
- sep = semiSep;
- else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
- sep = crlfSep;
- else
- sep = commaSep;
- sepLen = strlen(sep);
- if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
- rdnSep = spaceSep;
- else
- rdnSep = plusSep;
- rdnSepLen = strlen(rdnSep);
- for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
- {
- for (j = 0; (!psz || ret < csz) && j < rdn->cRDNAttr; j++)
- {
- DWORD chars;
- char prefixBuf[13]; /* big enough for SERIALNUMBER */
- LPCSTR prefix = NULL;
-
- if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
- prefix = rdn->rgRDNAttr[j].pszObjId;
- else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
- {
- PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
- CRYPT_OID_INFO_OID_KEY,
- rdn->rgRDNAttr[j].pszObjId,
- CRYPT_RDN_ATTR_OID_GROUP_ID);
-
- if (oidInfo)
- {
- WideCharToMultiByte(CP_ACP, 0, oidInfo->pwszName, -1,
- prefixBuf, sizeof(prefixBuf), NULL, NULL);
- prefix = prefixBuf;
- }
- else
- prefix = rdn->rgRDNAttr[j].pszObjId;
- }
- if (prefix)
- {
- /* - 1 is needed to account for the NULL terminator. */
- chars = CRYPT_AddPrefixA(prefix,
- psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
- ret += chars;
- }
- chars = quote_rdn_value_to_str_a(
- rdn->rgRDNAttr[j].dwValueType,
- &rdn->rgRDNAttr[j].Value, psz ? psz + ret : NULL,
- psz ? csz - ret : 0);
- if (chars)
- ret += chars - 1;
- if (j < rdn->cRDNAttr - 1)
- {
- if (psz && ret < csz - rdnSepLen - 1)
- memcpy(psz + ret, rdnSep, rdnSepLen);
- ret += rdnSepLen;
- }
- }
- if (i < info->cRDN - 1)
- {
- if (psz && ret < csz - sepLen - 1)
- memcpy(psz + ret, sep, sepLen);
- ret += sepLen;
- }
- if(reverse) rdn--;
- else rdn++;
- }
- LocalFree(info);
+ CryptMemFree(strW);
+ return len_mb;
}
- if (psz && csz)
+
+ ret = WideCharToMultiByte(CP_ACP, 0, strW, len, str, str_len, NULL, NULL);
+ if (ret < len_mb)
{
- *(psz + ret) = '\0';
- ret++;
+ str[0] = 0;
+ ret = 1;
}
- else
- ret++;
- TRACE("Returning %s\n", debugstr_a(psz));
+ CryptMemFree(strW);
return ret;
}
@@ -580,6 +330,7 @@ DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indentLevel,
DWORD ret = 0, bytes = 0;
BOOL bRet;
CERT_NAME_INFO *info;
+ DWORD chars;
if (dwStrType & unsupportedFlags)
FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags);
@@ -607,14 +358,17 @@ DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indentLevel,
else
rdnSep = L" + ";
rdnSepLen = lstrlenW(rdnSep);
- for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
+ if (!csz) psz = NULL;
+ for (i = 0; i < info->cRDN; i++)
{
- for (j = 0; (!psz || ret < csz) && j < rdn->cRDNAttr; j++)
+ if (psz && ret + 1 == csz) break;
+ for (j = 0; j < rdn->cRDNAttr; j++)
{
- DWORD chars;
LPCSTR prefixA = NULL;
LPCWSTR prefixW = NULL;
+ if (psz && ret + 1 == csz) break;
+
if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
prefixA = rdn->rgRDNAttr[j].pszObjId;
else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
@@ -644,6 +398,7 @@ DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indentLevel,
chars = lstrlenW(indent);
ret += chars;
}
+ if (psz && ret + 1 == csz) break;
}
if (prefixW)
{
@@ -659,38 +414,40 @@ DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indentLevel,
psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
ret += chars;
}
- chars = quote_rdn_value_to_str_w(
- rdn->rgRDNAttr[j].dwValueType,
- &rdn->rgRDNAttr[j].Value, psz ? psz + ret : NULL,
- psz ? csz - ret : 0);
- if (chars)
- ret += chars - 1;
+ if (psz && ret + 1 == csz) break;
+
+ chars = quote_rdn_value_to_str_w(rdn->rgRDNAttr[j].dwValueType, &rdn->rgRDNAttr[j].Value,
+ psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
+ ret += chars;
if (j < rdn->cRDNAttr - 1)
{
- if (psz && ret < csz - rdnSepLen - 1)
- memcpy(psz + ret, rdnSep, rdnSepLen * sizeof(WCHAR));
- ret += rdnSepLen;
+ if (psz)
+ {
+ chars = min(rdnSepLen, csz - ret - 1);
+ memcpy(psz + ret, rdnSep, chars * sizeof(WCHAR));
+ ret += chars;
+ }
+ else ret += rdnSepLen;
}
}
+ if (psz && ret + 1 == csz) break;
if (i < info->cRDN - 1)
{
- if (psz && ret < csz - sepLen - 1)
- memcpy(psz + ret, sep, sepLen * sizeof(WCHAR));
- ret += sepLen;
+ if (psz)
+ {
+ chars = min(sepLen, csz - ret - 1);
+ memcpy(psz + ret, sep, chars * sizeof(WCHAR));
+ ret += chars;
+ }
+ else ret += sepLen;
}
if(reverse) rdn--;
else rdn++;
}
LocalFree(info);
}
- if (psz && csz)
- {
- *(psz + ret) = '\0';
- ret++;
- }
- else
- ret++;
- return ret;
+ if (psz && csz) psz[ret] = 0;
+ return ret + 1;
}
DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
@@ -1113,49 +870,74 @@ BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500,
return ret;
}
-DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType,
- DWORD dwFlags, void *pvTypePara, LPSTR pszNameString, DWORD cchNameString)
+DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT cert, DWORD type,
+ DWORD flags, void *type_para, LPSTR name, DWORD name_len)
{
- DWORD ret;
+ DWORD len, len_mb, ret;
+ LPWSTR nameW;
+
+ TRACE("(%p, %ld, %08lx, %p, %p, %ld)\n", cert, type, flags, type_para, name, name_len);
- TRACE("(%p, %ld, %08lx, %p, %p, %ld)\n", pCertContext, dwType, dwFlags,
- pvTypePara, pszNameString, cchNameString);
+ len = CertGetNameStringW(cert, type, flags, type_para, NULL, 0);
- if (pszNameString)
+ if (!(nameW = CryptMemAlloc(len * sizeof(*nameW))))
{
- LPWSTR wideName;
- DWORD nameLen;
+ ERR("No memory.\n");
+ if (name && name_len) *name = 0;
+ return 1;
+ }
- nameLen = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
- NULL, 0);
- wideName = CryptMemAlloc(nameLen * sizeof(WCHAR));
- if (wideName)
- {
- CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
- wideName, nameLen);
- nameLen = WideCharToMultiByte(CP_ACP, 0, wideName, nameLen,
- pszNameString, cchNameString, NULL, NULL);
- if (nameLen <= cchNameString)
- ret = nameLen;
- else
- {
- pszNameString[cchNameString - 1] = '\0';
- ret = cchNameString;
- }
- CryptMemFree(wideName);
- }
- else
- {
- *pszNameString = '\0';
- ret = 1;
- }
+ len = CertGetNameStringW(cert, type, flags, type_para, nameW, len);
+ len_mb = WideCharToMultiByte(CP_ACP, 0, nameW, len, NULL, 0, NULL, NULL);
+ if (!name || !name_len)
+ {
+ CryptMemFree(nameW);
+ return len_mb;
}
- else
- ret = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
- NULL, 0);
+
+ ret = WideCharToMultiByte(CP_ACP, 0, nameW, len, name, name_len, NULL, NULL);
+ if (ret < len_mb)
+ {
+ name[0] = 0;
+ ret = 1;
+ }
+ CryptMemFree(nameW);
return ret;
}
+static BOOL cert_get_alt_name_info(PCCERT_CONTEXT cert, BOOL alt_name_issuer, PCERT_ALT_NAME_INFO *info)
+{
+ static const char *oids[][2] =
+ {
+ { szOID_SUBJECT_ALT_NAME2, szOID_SUBJECT_ALT_NAME },
+ { szOID_ISSUER_ALT_NAME2, szOID_ISSUER_ALT_NAME },
+ };
+ PCERT_EXTENSION ext;
+ DWORD bytes = 0;
+
+ ext = CertFindExtension(oids[!!alt_name_issuer][0], cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
+ if (!ext)
+ ext = CertFindExtension(oids[!!alt_name_issuer][1], cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
+ if (!ext) return FALSE;
+
+ return CryptDecodeObjectEx(cert->dwCertEncodingType, X509_ALTERNATE_NAME, ext->Value.pbData, ext->Value.cbData,
+ CRYPT_DECODE_ALLOC_FLAG, NULL, info, &bytes);
+}
+
+static PCERT_ALT_NAME_ENTRY cert_find_next_alt_name_entry(PCERT_ALT_NAME_INFO info, DWORD entry_type,
+ unsigned int *index)
+{
+ unsigned int i;
+
+ for (i = *index; i < info->cAltEntry; ++i)
+ if (info->rgAltEntry[i].dwAltNameChoice == entry_type)
+ {
+ *index = i + 1;
+ return &info->rgAltEntry[i];
+ }
+ return NULL;
+}
+
/* Searches cert's extensions for the alternate name extension with OID
* altNameOID, and if found, searches it for the alternate name type entryType.
* If found, returns a pointer to the entry, otherwise returns NULL.
@@ -1165,31 +947,13 @@ DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType,
* The return value is a pointer within *info, so don't free *info before
* you're done with the return value.
*/
-static PCERT_ALT_NAME_ENTRY cert_find_alt_name_entry(PCCERT_CONTEXT cert,
- LPCSTR altNameOID, DWORD entryType, PCERT_ALT_NAME_INFO *info)
+static PCERT_ALT_NAME_ENTRY cert_find_alt_name_entry(PCCERT_CONTEXT cert, BOOL alt_name_issuer,
+ DWORD entry_type, PCERT_ALT_NAME_INFO *info)
{
- PCERT_ALT_NAME_ENTRY entry = NULL;
- PCERT_EXTENSION ext = CertFindExtension(altNameOID,
- cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
-
- if (ext)
- {
- DWORD bytes = 0;
+ unsigned int index = 0;
- if (CryptDecodeObjectEx(cert->dwCertEncodingType, X509_ALTERNATE_NAME,
- ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
- info, &bytes))
- {
- DWORD i;
-
- for (i = 0; !entry && i < (*info)->cAltEntry; i++)
- if ((*info)->rgAltEntry[i].dwAltNameChoice == entryType)
- entry = &(*info)->rgAltEntry[i];
- }
- }
- else
- *info = NULL;
- return entry;
+ if (!cert_get_alt_name_info(cert, alt_name_issuer, info)) return NULL;
+ return cert_find_next_alt_name_entry(*info, entry_type, &index);
}
static DWORD cert_get_name_from_rdn_attr(DWORD encodingType,
@@ -1207,222 +971,195 @@ static DWORD cert_get_name_from_rdn_attr(DWORD encodingType,
oid = szOID_RSA_emailAddr;
nameAttr = CertFindRDNAttr(oid, nameInfo);
if (nameAttr)
- ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value,
- pszNameString, cchNameString);
+ ret = rdn_value_to_strW(nameAttr->dwValueType, &nameAttr->Value,
+ pszNameString, cchNameString, TRUE);
LocalFree(nameInfo);
}
return ret;
}
-DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType,
- DWORD dwFlags, void *pvTypePara, LPWSTR pszNameString, DWORD cchNameString)
+static DWORD copy_output_str(WCHAR *dst, const WCHAR *src, DWORD dst_size)
{
- DWORD ret = 0;
+ DWORD len = wcslen(src);
+
+ if (!dst || !dst_size) return len + 1;
+ len = min(len, dst_size - 1);
+ memcpy(dst, src, len * sizeof(*dst));
+ dst[len] = 0;
+ return len + 1;
+}
+
+DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT cert, DWORD type, DWORD flags, void *type_para,
+ LPWSTR name_string, DWORD name_len)
+{
+ static const DWORD supported_flags = CERT_NAME_ISSUER_FLAG | CERT_NAME_SEARCH_ALL_NAMES_FLAG;
+ BOOL alt_name_issuer, search_all_names;
+ CERT_ALT_NAME_INFO *info = NULL;
+ PCERT_ALT_NAME_ENTRY entry;
PCERT_NAME_BLOB name;
- LPCSTR altNameOID;
+ DWORD ret = 0;
- TRACE("(%p, %ld, %08lx, %p, %p, %ld)\n", pCertContext, dwType,
- dwFlags, pvTypePara, pszNameString, cchNameString);
+ TRACE("(%p, %ld, %08lx, %p, %p, %ld)\n", cert, type, flags, type_para, name_string, name_len);
- if (!pCertContext)
+ if (!cert)
goto done;
- if (dwFlags & CERT_NAME_ISSUER_FLAG)
- {
- name = &pCertContext->pCertInfo->Issuer;
- altNameOID = szOID_ISSUER_ALT_NAME;
- }
- else
+ if (flags & ~supported_flags)
+ FIXME("Unsupported flags %#lx.\n", flags);
+
+ search_all_names = flags & CERT_NAME_SEARCH_ALL_NAMES_FLAG;
+ if (search_all_names && type != CERT_NAME_DNS_TYPE)
{
- name = &pCertContext->pCertInfo->Subject;
- altNameOID = szOID_SUBJECT_ALT_NAME;
+ WARN("CERT_NAME_SEARCH_ALL_NAMES_FLAG used with type %lu.\n", type);
+ goto done;
}
- switch (dwType)
+ alt_name_issuer = flags & CERT_NAME_ISSUER_FLAG;
+ name = alt_name_issuer ? &cert->pCertInfo->Issuer : &cert->pCertInfo->Subject;
+
+ switch (type)
{
case CERT_NAME_EMAIL_TYPE:
{
- CERT_ALT_NAME_INFO *info;
- PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
- altNameOID, CERT_ALT_NAME_RFC822_NAME, &info);
+ entry = cert_find_alt_name_entry(cert, alt_name_issuer, CERT_ALT_NAME_RFC822_NAME, &info);
if (entry)
{
- if (!pszNameString)
- ret = lstrlenW(entry->u.pwszRfc822Name) + 1;
- else if (cchNameString)
- {
- ret = min(lstrlenW(entry->u.pwszRfc822Name), cchNameString - 1);
- memcpy(pszNameString, entry->u.pwszRfc822Name,
- ret * sizeof(WCHAR));
- pszNameString[ret++] = 0;
- }
+ ret = copy_output_str(name_string, entry->u.pwszRfc822Name, name_len);
+ break;
}
- if (info)
- LocalFree(info);
- if (!ret)
- ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
- name, szOID_RSA_emailAddr, pszNameString, cchNameString);
+ ret = cert_get_name_from_rdn_attr(cert->dwCertEncodingType, name, szOID_RSA_emailAddr,
+ name_string, name_len);
break;
}
case CERT_NAME_RDN_TYPE:
{
- DWORD type = pvTypePara ? *(DWORD *)pvTypePara : 0;
+ DWORD param = type_para ? *(DWORD *)type_para : 0;
if (name->cbData)
- ret = CertNameToStrW(pCertContext->dwCertEncodingType, name,
- type, pszNameString, cchNameString);
+ {
+ ret = CertNameToStrW(cert->dwCertEncodingType, name, param, name_string, name_len);
+ }
else
{
- CERT_ALT_NAME_INFO *info;
- PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
- altNameOID, CERT_ALT_NAME_DIRECTORY_NAME, &info);
+ entry = cert_find_alt_name_entry(cert, alt_name_issuer, CERT_ALT_NAME_DIRECTORY_NAME, &info);
if (entry)
- ret = CertNameToStrW(pCertContext->dwCertEncodingType,
- &entry->u.DirectoryName, type, pszNameString, cchNameString);
- if (info)
- LocalFree(info);
+ ret = CertNameToStrW(cert->dwCertEncodingType, &entry->u.DirectoryName,
+ param, name_string, name_len);
}
break;
}
case CERT_NAME_ATTR_TYPE:
- ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
- name, pvTypePara, pszNameString, cchNameString);
- if (!ret)
- {
- CERT_ALT_NAME_INFO *altInfo;
- PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
- altNameOID, CERT_ALT_NAME_DIRECTORY_NAME, &altInfo);
+ ret = cert_get_name_from_rdn_attr(cert->dwCertEncodingType, name, type_para,
+ name_string, name_len);
+ if (ret) break;
- if (entry)
- ret = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0,
- &entry->u.DirectoryName, 0, pszNameString, cchNameString);
- if (altInfo)
- LocalFree(altInfo);
- }
+ entry = cert_find_alt_name_entry(cert, alt_name_issuer, CERT_ALT_NAME_DIRECTORY_NAME, &info);
+
+ if (entry)
+ ret = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, &entry->u.DirectoryName,
+ 0, name_string, name_len);
break;
case CERT_NAME_SIMPLE_DISPLAY_TYPE:
{
- static const LPCSTR simpleAttributeOIDs[] = { szOID_COMMON_NAME,
- szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME,
- szOID_RSA_emailAddr };
+ static const LPCSTR simpleAttributeOIDs[] =
+ {
+ szOID_COMMON_NAME, szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME, szOID_RSA_emailAddr
+ };
CERT_NAME_INFO *nameInfo = NULL;
DWORD bytes = 0, i;
- if (CryptDecodeObjectEx(pCertContext->dwCertEncodingType, X509_NAME,
- name->pbData, name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo,
- &bytes))
+ if (CryptDecodeObjectEx(cert->dwCertEncodingType, X509_NAME, name->pbData, name->cbData,
+ CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo, &bytes))
{
PCERT_RDN_ATTR nameAttr = NULL;
for (i = 0; !nameAttr && i < ARRAY_SIZE(simpleAttributeOIDs); i++)
nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], nameInfo);
if (nameAttr)
- ret = CertRDNValueToStrW(nameAttr->dwValueType,
- &nameAttr->Value, pszNameString, cchNameString);
+ ret = rdn_value_to_strW(nameAttr->dwValueType, &nameAttr->Value, name_string, name_len, TRUE);
LocalFree(nameInfo);
}
- if (!ret)
- {
- CERT_ALT_NAME_INFO *altInfo;
- PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
- altNameOID, CERT_ALT_NAME_RFC822_NAME, &altInfo);
-
- if (altInfo)
- {
- if (!entry && altInfo->cAltEntry)
- entry = &altInfo->rgAltEntry[0];
- if (entry)
- {
- if (!pszNameString)
- ret = lstrlenW(entry->u.pwszRfc822Name) + 1;
- else if (cchNameString)
- {
- ret = min(lstrlenW(entry->u.pwszRfc822Name),
- cchNameString - 1);
- memcpy(pszNameString, entry->u.pwszRfc822Name,
- ret * sizeof(WCHAR));
- pszNameString[ret++] = 0;
- }
- }
- LocalFree(altInfo);
- }
- }
+ if (ret) break;
+ entry = cert_find_alt_name_entry(cert, alt_name_issuer, CERT_ALT_NAME_RFC822_NAME, &info);
+ if (!info) break;
+ if (!entry && info->cAltEntry)
+ entry = &info->rgAltEntry[0];
+ if (entry) ret = copy_output_str(name_string, entry->u.pwszRfc822Name, name_len);
break;
}
case CERT_NAME_FRIENDLY_DISPLAY_TYPE:
{
- DWORD cch = cchNameString;
+ DWORD len = name_len;
- if (CertGetCertificateContextProperty(pCertContext,
- CERT_FRIENDLY_NAME_PROP_ID, pszNameString, &cch))
- ret = cch;
+ if (CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, name_string, &len))
+ ret = len;
else
- ret = CertGetNameStringW(pCertContext,
- CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, pvTypePara, pszNameString,
- cchNameString);
+ ret = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, flags,
+ type_para, name_string, name_len);
break;
}
case CERT_NAME_DNS_TYPE:
{
- CERT_ALT_NAME_INFO *info;
- PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
- altNameOID, CERT_ALT_NAME_DNS_NAME, &info);
+ unsigned int index = 0, len;
- if (entry)
+ if (cert_get_alt_name_info(cert, alt_name_issuer, &info)
+ && (entry = cert_find_next_alt_name_entry(info, CERT_ALT_NAME_DNS_NAME, &index)))
{
- if (!pszNameString)
- ret = lstrlenW(entry->u.pwszDNSName) + 1;
- else if (cchNameString)
+ if (search_all_names)
{
- ret = min(lstrlenW(entry->u.pwszDNSName), cchNameString - 1);
- memcpy(pszNameString, entry->u.pwszDNSName, ret * sizeof(WCHAR));
- pszNameString[ret++] = 0;
+ do
+ {
+ if (name_string && name_len == 1) break;
+ ret += len = copy_output_str(name_string, entry->u.pwszDNSName, name_len ? name_len - 1 : 0);
+ if (name_string && name_len)
+ {
+ name_string += len;
+ name_len -= len;
+ }
+ }
+ while ((entry = cert_find_next_alt_name_entry(info, CERT_ALT_NAME_DNS_NAME, &index)));
}
+ else ret = copy_output_str(name_string, entry->u.pwszDNSName, name_len);
}
- if (info)
- LocalFree(info);
- if (!ret)
- ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
- name, szOID_COMMON_NAME, pszNameString, cchNameString);
- break;
- }
- case CERT_NAME_URL_TYPE:
- {
- CERT_ALT_NAME_INFO *info;
- PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
- altNameOID, CERT_ALT_NAME_URL, &info);
-
- if (entry)
+ else
{
- if (!pszNameString)
- ret = lstrlenW(entry->u.pwszURL) + 1;
- else if (cchNameString)
+ if (!search_all_names || name_len != 1)
{
- ret = min(lstrlenW(entry->u.pwszURL), cchNameString - 1);
- memcpy(pszNameString, entry->u.pwszURL, ret * sizeof(WCHAR));
- pszNameString[ret++] = 0;
+ len = search_all_names && name_len ? name_len - 1 : name_len;
+ ret = cert_get_name_from_rdn_attr(cert->dwCertEncodingType, name, szOID_COMMON_NAME,
+ name_string, len);
+ if (name_string) name_string += ret;
}
}
- if (info)
- LocalFree(info);
+
+ if (search_all_names)
+ {
+ if (name_string && name_len) *name_string = 0;
+ ++ret;
+ }
+ break;
+ }
+ case CERT_NAME_URL_TYPE:
+ {
+ if ((entry = cert_find_alt_name_entry(cert, alt_name_issuer, CERT_ALT_NAME_URL, &info)))
+ ret = copy_output_str(name_string, entry->u.pwszURL, name_len);
break;
}
default:
- FIXME("unimplemented for type %ld\n", dwType);
+ FIXME("unimplemented for type %lu.\n", type);
ret = 0;
+ break;
}
done:
+ if (info)
+ LocalFree(info);
+
if (!ret)
{
- if (!pszNameString)
- ret = 1;
- else if (cchNameString)
- {
- pszNameString[0] = 0;
- ret = 1;
- }
+ ret = 1;
+ if (name_string && name_len) name_string[0] = 0;
}
return ret;
}
diff --git a/dlls/crypt32/tests/base64.c b/dlls/crypt32/tests/base64.c
index a1517b294ad..e81a57c576d 100644
--- wine/dlls/crypt32/tests/base64.c
+++ wine/dlls/crypt32/tests/base64.c
@@ -23,7 +23,6 @@
#include <windows.h>
#include <wincrypt.h>
-#include "wine/heap.h"
#include "wine/test.h"
#define CERT_HEADER "-----BEGIN CERTIFICATE-----\r\n"
@@ -93,7 +92,7 @@ static WCHAR *strdupAtoW(const char *str)
if (!str) return ret;
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
- ret = heap_alloc(len * sizeof(WCHAR));
+ ret = malloc(len * sizeof(WCHAR));
if (ret)
MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
return ret;
@@ -128,7 +127,7 @@ static void encodeAndCompareBase64_A(const BYTE *toEncode, DWORD toEncodeLen,
ok(ret, "CryptBinaryToStringA failed: %ld\n", GetLastError());
ok(strLen == strLen2, "Unexpected required length %lu, expected %lu.\n", strLen2, strLen);
- str = heap_alloc(strLen);
+ str = malloc(strLen);
/* Partially filled output buffer. */
strLen2 = strLen - 1;
@@ -157,7 +156,7 @@ static void encodeAndCompareBase64_A(const BYTE *toEncode, DWORD toEncodeLen,
if (trailer)
ok(!strncmp(trailer, ptr, strlen(trailer)), "Expected trailer %s, got %s\n", trailer, ptr);
- heap_free(str);
+ free(str);
}
static void encode_compare_base64_W(const BYTE *toEncode, DWORD toEncodeLen, DWORD format,
@@ -196,7 +195,7 @@ static void encode_compare_base64_W(const BYTE *toEncode, DWORD toEncodeLen, DWO
ok(ret, "CryptBinaryToStringW failed: %ld\n", GetLastError());
ok(strLen == strLen2, "Unexpected required length.\n");
- strW = heap_alloc(strLen * sizeof(WCHAR));
+ strW = malloc(strLen * sizeof(WCHAR));
headerW = strdupAtoW(header);
trailerW = strdupAtoW(trailer);
@@ -231,9 +230,9 @@ static void encode_compare_base64_W(const BYTE *toEncode, DWORD toEncodeLen, DWO
ok(!memcmp(trailerW, ptr, lstrlenW(trailerW)), "Expected trailer %s, got %s.\n", wine_dbgstr_w(trailerW),
wine_dbgstr_w(ptr));
- heap_free(strW);
- heap_free(headerW);
- heap_free(trailerW);
+ free(strW);
+ free(headerW);
+ free(trailerW);
}
static DWORD binary_to_hex_len(DWORD binary_len, DWORD flags)
@@ -267,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);
@@ -299,12 +299,12 @@ static void test_CryptBinaryToString(void)
ok(strLen == tests[i].toEncodeLen, "Unexpected required length %lu.\n", strLen);
strLen2 = strLen;
- str = heap_alloc(strLen);
+ str = malloc(strLen);
ret = CryptBinaryToStringA(tests[i].toEncode, tests[i].toEncodeLen, CRYPT_STRING_BINARY, str, &strLen2);
ok(ret, "CryptBinaryToStringA failed: %ld\n", GetLastError());
ok(strLen == strLen2, "Expected length %lu, got %lu\n", strLen, strLen2);
ok(!memcmp(str, tests[i].toEncode, tests[i].toEncodeLen), "Unexpected value\n");
- heap_free(str);
+ free(str);
strLen = 0;
ret = CryptBinaryToStringW(tests[i].toEncode, tests[i].toEncodeLen, CRYPT_STRING_BINARY, NULL, &strLen);
@@ -312,12 +312,12 @@ static void test_CryptBinaryToString(void)
ok(strLen == tests[i].toEncodeLen, "Unexpected required length %lu.\n", strLen);
strLen2 = strLen;
- strW = heap_alloc(strLen);
+ strW = malloc(strLen);
ret = CryptBinaryToStringW(tests[i].toEncode, tests[i].toEncodeLen, CRYPT_STRING_BINARY, strW, &strLen2);
ok(ret, "CryptBinaryToStringW failed: %ld\n", GetLastError());
ok(strLen == strLen2, "Expected length %lu, got %lu\n", strLen, strLen2);
ok(!memcmp(strW, tests[i].toEncode, tests[i].toEncodeLen), "Unexpected value\n");
- heap_free(strW);
+ free(strW);
encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen, CRYPT_STRING_BASE64,
tests[i].base64, NULL, NULL);
@@ -338,7 +338,7 @@ static void test_CryptBinaryToString(void)
encode_compare_base64_W(tests[i].toEncode, tests[i].toEncodeLen, CRYPT_STRING_BASE64X509CRLHEADER, encodedW,
X509_HEADER, X509_TRAILER);
- heap_free(encodedW);
+ free(encodedW);
}
for (i = 0; i < ARRAY_SIZE(testsNoCR); i++)
@@ -352,13 +352,13 @@ static void test_CryptBinaryToString(void)
ok(ret, "CryptBinaryToStringA failed: %ld\n", GetLastError());
strLen2 = strLen;
- str = heap_alloc(strLen);
+ str = malloc(strLen);
ret = CryptBinaryToStringA(testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen,
CRYPT_STRING_BINARY | CRYPT_STRING_NOCR, str, &strLen2);
ok(ret, "CryptBinaryToStringA failed: %ld\n", GetLastError());
ok(strLen == strLen2, "Expected length %ld, got %ld\n", strLen, strLen2);
ok(!memcmp(str, testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen), "Unexpected value\n");
- heap_free(str);
+ free(str);
encodeAndCompareBase64_A(testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR,
testsNoCR[i].base64, NULL, NULL);
@@ -383,7 +383,7 @@ static void test_CryptBinaryToString(void)
CRYPT_STRING_BASE64X509CRLHEADER | CRYPT_STRING_NOCR, encodedW,
X509_HEADER_NOCR, X509_TRAILER_NOCR);
- heap_free(encodedW);
+ free(encodedW);
}
/* Systems that don't support HEXRAW format convert to BASE64 instead - 3 bytes in -> 4 chars + crlf + 1 null out. */
@@ -402,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,9 +426,12 @@ static void test_CryptBinaryToString(void)
strLen2 += sizeof(input) * 2 + 1;
ok(strLen == strLen2, "Expected length %ld, got %ld\n", strLen2, strLen);
- hex = heap_alloc(strLen * sizeof(WCHAR));
+ hex = malloc(strLen * sizeof(WCHAR));
+ hex_a = malloc(strLen);
+
memset(hex, 0xcc, strLen * sizeof(WCHAR));
- ptr = cmp = heap_alloc(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];
@@ -438,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());
@@ -445,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],
@@ -452,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;
@@ -465,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");
- heap_free(hex);
- heap_free(cmp);
+ 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++)
@@ -483,10 +551,10 @@ static void test_CryptBinaryToString(void)
strLen2 = binary_to_hex_len(sizes[k], CRYPT_STRING_HEX | flags[i]);
ok(strLen == strLen2, "%lu: Expected length %ld, got %ld\n", i, strLen2, strLen);
- hex = heap_alloc(strLen * sizeof(WCHAR) + 256);
+ hex = malloc(strLen * sizeof(WCHAR) + 256);
memset(hex, 0xcc, strLen * sizeof(WCHAR));
- ptr = cmp = heap_alloc(strLen * sizeof(WCHAR) + 256);
+ ptr = cmp = malloc(strLen * sizeof(WCHAR) + 256);
for (j = 0; j < sizes[k]; j++)
{
*ptr++ = hexdig[(input[j] >> 4) & 0xf];
@@ -552,8 +620,8 @@ static void test_CryptBinaryToString(void)
ok(strLen == strLen2, "%lu: Expected length %ld, got %ld\n", i, strLen, strLen2);
ok(!memcmp(hex, cmp, strLen * sizeof(WCHAR)), "%lu: got %s\n", i, wine_dbgstr_wn(hex, strLen));
- heap_free(hex);
- heap_free(cmp);
+ free(hex);
+ free(cmp);
}
}
@@ -569,7 +637,7 @@ static void decodeAndCompareBase64_A(LPCSTR toDecode, LPCSTR header,
len += strlen(header);
if (trailer)
len += strlen(trailer);
- str = HeapAlloc(GetProcessHeap(), 0, len);
+ str = malloc(len);
if (str)
{
LPBYTE buf;
@@ -586,7 +654,7 @@ static void decodeAndCompareBase64_A(LPCSTR toDecode, LPCSTR header,
ret = CryptStringToBinaryA(str, 0, useFormat, NULL, &bufLen, NULL,
NULL);
ok(ret, "CryptStringToBinaryA failed: %ld\n", GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, bufLen);
+ buf = malloc(bufLen);
if (buf)
{
DWORD skipped, usedFormat;
@@ -605,7 +673,7 @@ static void decodeAndCompareBase64_A(LPCSTR toDecode, LPCSTR header,
ok(skipped == 0, "Expected skipped 0, got %ld\n", skipped);
ok(usedFormat == expectedFormat, "Expected format %ld, got %ld\n",
expectedFormat, usedFormat);
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
/* Check again, but with garbage up front */
@@ -625,7 +693,7 @@ static void decodeAndCompareBase64_A(LPCSTR toDecode, LPCSTR header,
"Expected !ret and last error ERROR_INVALID_DATA, got ret=%d, error=%ld\n", ret, GetLastError());
if (ret)
{
- buf = HeapAlloc(GetProcessHeap(), 0, bufLen);
+ buf = malloc(bufLen);
if (buf)
{
DWORD skipped, usedFormat;
@@ -636,10 +704,10 @@ static void decodeAndCompareBase64_A(LPCSTR toDecode, LPCSTR header,
ok(skipped == strlen(garbage),
"Expected %d characters of \"%s\" skipped when trying format %08lx, got %ld (used format is %08lx)\n",
lstrlenA(garbage), str, useFormat, skipped, usedFormat);
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
}
- HeapFree(GetProcessHeap(), 0, str);
+ free(str);
}
}
@@ -707,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,
@@ -891,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();
}
diff --git a/dlls/crypt32/tests/cert.c b/dlls/crypt32/tests/cert.c
index 3cdb5e5ceea..882bb4a0723 100644
--- wine/dlls/crypt32/tests/cert.c
+++ wine/dlls/crypt32/tests/cert.c
@@ -554,7 +554,7 @@ static void testCertProperties(void)
ok(ret, "CertGetCertificateContextProperty failed: %08lx\n", GetLastError());
if (ret)
{
- LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size);
+ LPBYTE buf = malloc(size);
if (buf)
{
@@ -563,7 +563,7 @@ static void testCertProperties(void)
ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
GetLastError());
ok(!memcmp(buf, subjectKeyId, size), "Unexpected subject key id\n");
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
}
CertFreeCertificateContext(context);
@@ -1640,7 +1640,7 @@ static void testGetIssuerCert(void)
size = 0;
ok(CertStrToNameW(X509_ASN_ENCODING, L"CN=dummy, T=Test", CERT_X500_NAME_STR, NULL, NULL, &size, NULL),
"CertStrToName should have worked\n");
- certencoded = HeapAlloc(GetProcessHeap(), 0, size);
+ certencoded = malloc(size);
ok(CertStrToNameW(X509_ASN_ENCODING, L"CN=dummy, T=Test", CERT_X500_NAME_STR, NULL, certencoded, &size, NULL),
"CertStrToName should have worked\n");
certsubject.pbData = certencoded;
@@ -1663,7 +1663,7 @@ static void testGetIssuerCert(void)
CertFreeCertificateContext(cert2);
CertFreeCertificateContext(cert3);
CertCloseStore(store, 0);
- HeapFree(GetProcessHeap(), 0, certencoded);
+ free(certencoded);
/* Test root storage self-signed certificate */
store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT");
@@ -1913,7 +1913,7 @@ static void testVerifyCertSig(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
}
CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
(LPSTR)sigOID, 0, NULL, NULL, &pubKeySize);
- pubKeyInfo = HeapAlloc(GetProcessHeap(), 0, pubKeySize);
+ pubKeyInfo = malloc(pubKeySize);
if (pubKeyInfo)
{
ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
@@ -1927,7 +1927,7 @@ static void testVerifyCertSig(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
ok(ret, "CryptVerifyCertificateSignature failed: %08lx\n",
GetLastError());
}
- HeapFree(GetProcessHeap(), 0, pubKeyInfo);
+ free(pubKeyInfo);
}
LocalFree(cert);
}
@@ -2000,7 +2000,7 @@ static void testVerifyCertSigEx(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigne
*/
CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
(LPSTR)sigOID, 0, NULL, NULL, &size);
- pubKeyInfo = HeapAlloc(GetProcessHeap(), 0, size);
+ pubKeyInfo = malloc(size);
if (pubKeyInfo)
{
ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
@@ -2014,7 +2014,7 @@ static void testVerifyCertSigEx(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigne
ok(ret, "CryptVerifyCertificateSignatureEx failed: %08lx\n",
GetLastError());
}
- HeapFree(GetProcessHeap(), 0, pubKeyInfo);
+ free(pubKeyInfo);
}
LocalFree(cert);
}
@@ -2114,7 +2114,7 @@ static void testSignAndEncodeCert(void)
/* oid_rsa_md5 not present in some win2k */
if (ret)
{
- LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size);
+ LPBYTE buf = malloc(size);
if (buf)
{
@@ -2135,7 +2135,7 @@ static void testSignAndEncodeCert(void)
else if (size == sizeof(md5SignedEmptyCertNoNull))
ok(!memcmp(buf, md5SignedEmptyCertNoNull, size),
"Unexpected value\n");
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
}
}
@@ -2188,7 +2188,7 @@ static void testCreateSelfSignCert(void)
ok(ret && size, "Expected non-zero key provider info\n");
if (size)
{
- PCRYPT_KEY_PROV_INFO pInfo = HeapAlloc(GetProcessHeap(), 0, size);
+ PCRYPT_KEY_PROV_INFO pInfo = malloc(size);
if (pInfo)
{
@@ -2206,7 +2206,7 @@ static void testCreateSelfSignCert(void)
ok(pInfo->dwKeySpec == AT_SIGNATURE,
"Expected AT_SIGNATURE, got %ld\n", pInfo->dwKeySpec);
}
- HeapFree(GetProcessHeap(), 0, pInfo);
+ free(pInfo);
}
}
@@ -2262,7 +2262,7 @@ static void testCreateSelfSignCert(void)
ok(ret && size, "Expected non-zero key provider info\n");
if (size)
{
- PCRYPT_KEY_PROV_INFO pInfo = HeapAlloc(GetProcessHeap(), 0, size);
+ PCRYPT_KEY_PROV_INFO pInfo = malloc(size);
if (pInfo)
{
@@ -2280,7 +2280,7 @@ static void testCreateSelfSignCert(void)
ok(pInfo->dwKeySpec == AT_SIGNATURE,
"Expected AT_SIGNATURE, got %ld\n", pInfo->dwKeySpec);
}
- HeapFree(GetProcessHeap(), 0, pInfo);
+ free(pInfo);
}
}
@@ -2309,7 +2309,7 @@ static void testCreateSelfSignCert(void)
ok(ret && size, "Expected non-zero key provider info\n");
if (size)
{
- PCRYPT_KEY_PROV_INFO pInfo = HeapAlloc(GetProcessHeap(), 0, size);
+ PCRYPT_KEY_PROV_INFO pInfo = malloc(size);
if (pInfo)
{
@@ -2327,7 +2327,7 @@ static void testCreateSelfSignCert(void)
ok(pInfo->dwKeySpec == AT_KEYEXCHANGE,
"Expected AT_KEYEXCHANGE, got %ld\n", pInfo->dwKeySpec);
}
- HeapFree(GetProcessHeap(), 0, pInfo);
+ free(pInfo);
}
}
@@ -2386,7 +2386,7 @@ static void testCreateSelfSignCert(void)
ok(ret && size, "Expected non-zero key provider info\n");
if (size)
{
- PCRYPT_KEY_PROV_INFO pInfo = HeapAlloc(GetProcessHeap(), 0, size);
+ PCRYPT_KEY_PROV_INFO pInfo = malloc(size);
if (pInfo)
{
@@ -2404,7 +2404,7 @@ static void testCreateSelfSignCert(void)
ok(pInfo->dwKeySpec == AT_KEYEXCHANGE,
"Expected AT_KEYEXCHANGE, got %ld\n", pInfo->dwKeySpec);
}
- HeapFree(GetProcessHeap(), 0, pInfo);
+ free(pInfo);
}
}
@@ -2627,7 +2627,7 @@ static void testKeyUsage(void)
ret = CertGetEnhancedKeyUsage(context,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize);
ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
+ buf = malloc(bufSize);
if (buf)
{
PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
@@ -2644,11 +2644,11 @@ static void testKeyUsage(void)
ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
"Expected %s, got %s\n", keyUsages[i],
pUsage->rgpszUsageIdentifier[i]);
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
+ buf = malloc(bufSize);
if (buf)
{
PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
@@ -2668,7 +2668,7 @@ static void testKeyUsage(void)
ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
"Expected %s, got %s\n", keyUsages[i],
pUsage->rgpszUsageIdentifier[i]);
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
/* Shouldn't find it as an extended property */
ret = CertGetEnhancedKeyUsage(context,
@@ -2681,7 +2681,7 @@ static void testKeyUsage(void)
GetLastError());
ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
+ buf = malloc(bufSize);
if (buf)
{
PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
@@ -2696,13 +2696,13 @@ static void testKeyUsage(void)
ok(!strcmp(pUsage->rgpszUsageIdentifier[0], szOID_RSA_RSA),
"Expected %s, got %s\n", szOID_RSA_RSA,
pUsage->rgpszUsageIdentifier[0]);
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
/* But querying the cert directly returns its usage */
ret = CertGetEnhancedKeyUsage(context,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize);
ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
+ buf = malloc(bufSize);
if (buf)
{
PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
@@ -2718,7 +2718,7 @@ static void testKeyUsage(void)
ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
"Expected %s, got %s\n", keyUsages[i],
pUsage->rgpszUsageIdentifier[i]);
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
/* And removing the only usage identifier in the extended property
* results in the cert's key usage being found.
@@ -2727,7 +2727,7 @@ static void testKeyUsage(void)
ok(ret, "CertRemoveEnhancedKeyUsage failed: %08lx\n", GetLastError());
ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
+ buf = malloc(bufSize);
if (buf)
{
PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
@@ -2743,7 +2743,7 @@ static void testKeyUsage(void)
ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
"Expected %s, got %s\n", keyUsages[i],
pUsage->rgpszUsageIdentifier[i]);
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
CertFreeCertificateContext(context);
@@ -2810,7 +2810,7 @@ static void testGetValidUsages(void)
ok(ret, "CertGetValidUsages failed: %08lx\n", GetLastError());
ok(numOIDs == 3, "Expected 3, got %d\n", numOIDs);
ok(size, "Expected non-zero size\n");
- oids = HeapAlloc(GetProcessHeap(), 0, size);
+ oids = malloc(size);
if (oids)
{
int i;
@@ -2825,7 +2825,7 @@ static void testGetValidUsages(void)
for (i = 0; i < numOIDs; i++)
ok(!lstrcmpA(oids[i], expectedOIDs[i]), "unexpected OID %s\n",
oids[i]);
- HeapFree(GetProcessHeap(), 0, oids);
+ free(oids);
}
numOIDs = 0xdeadbeef;
/* Oddly enough, this crashes when the number of contexts is not 1:
@@ -2837,7 +2837,7 @@ static void testGetValidUsages(void)
ok(ret, "CertGetValidUsages failed: %08lx\n", GetLastError());
ok(numOIDs == 3, "Expected 3, got %d\n", numOIDs);
ok(size, "Expected non-zero size\n");
- oids = HeapAlloc(GetProcessHeap(), 0, size);
+ oids = malloc(size);
if (oids)
{
int i;
@@ -2847,7 +2847,7 @@ static void testGetValidUsages(void)
for (i = 0; i < numOIDs; i++)
ok(!lstrcmpA(oids[i], expectedOIDs[i]), "unexpected OID %s\n",
oids[i]);
- HeapFree(GetProcessHeap(), 0, oids);
+ free(oids);
}
numOIDs = 0xdeadbeef;
size = 0;
@@ -2855,7 +2855,7 @@ static void testGetValidUsages(void)
ok(ret, "CertGetValidUsages failed: %08lx\n", GetLastError());
ok(numOIDs == 2, "Expected 2, got %d\n", numOIDs);
ok(size, "Expected non-zero size\n");
- oids = HeapAlloc(GetProcessHeap(), 0, size);
+ oids = malloc(size);
if (oids)
{
int i;
@@ -2865,7 +2865,7 @@ static void testGetValidUsages(void)
for (i = 0; i < numOIDs; i++)
ok(!lstrcmpA(oids[i], expectedOIDs2[i]), "unexpected OID %s\n",
oids[i]);
- HeapFree(GetProcessHeap(), 0, oids);
+ free(oids);
}
numOIDs = 0xdeadbeef;
size = 0;
@@ -2873,7 +2873,7 @@ static void testGetValidUsages(void)
ok(ret, "CertGetValidUsages failed: %08lx\n", GetLastError());
ok(numOIDs == 2, "Expected 2, got %d\n", numOIDs);
ok(size, "Expected non-zero size\n");
- oids = HeapAlloc(GetProcessHeap(), 0, size);
+ oids = malloc(size);
if (oids)
{
int i;
@@ -2883,7 +2883,7 @@ static void testGetValidUsages(void)
for (i = 0; i < numOIDs; i++)
ok(!lstrcmpA(oids[i], expectedOIDs2[i]), "unexpected OID %s\n",
oids[i]);
- HeapFree(GetProcessHeap(), 0, oids);
+ free(oids);
}
CertFreeCertificateContext(contexts[0]);
CertFreeCertificateContext(contexts[1]);
@@ -3537,6 +3537,520 @@ static const BYTE rootSignedCRL[] = {
0xd5,0xbc,0xb0,0xd5,0xa5,0x9c,0x1b,0x72,0xc3,0x0f,0xa3,0xe3,0x3c,0xf0,0xc3,
0x91,0xe8,0x93,0x4f,0xd4,0x2f };
+static const BYTE ocsp_cert[] = {
+ 0x30, 0x82, 0x06, 0xcd, 0x30, 0x82, 0x05, 0xb5, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x10, 0x08, 0x49, 0x8f, 0x6d, 0xd9, 0xef, 0xfb, 0x40, 0x55,
+ 0x1e, 0xac, 0x54, 0x54, 0x87, 0xc1, 0xb1, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x4f,
+ 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+ 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c,
+ 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63,
+ 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x20, 0x44,
+ 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x54, 0x4c, 0x53, 0x20,
+ 0x52, 0x53, 0x41, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x32,
+ 0x30, 0x32, 0x30, 0x20, 0x43, 0x41, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32,
+ 0x31, 0x30, 0x34, 0x32, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
+ 0x17, 0x0d, 0x32, 0x32, 0x30, 0x35, 0x32, 0x39, 0x32, 0x33, 0x35, 0x39,
+ 0x35, 0x39, 0x5a, 0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+ 0x55, 0x04, 0x08, 0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67,
+ 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
+ 0x13, 0x08, 0x42, 0x65, 0x6c, 0x6c, 0x65, 0x76, 0x75, 0x65, 0x31, 0x14,
+ 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x56, 0x61, 0x6c,
+ 0x76, 0x65, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x2e, 0x31, 0x1e, 0x30, 0x1c,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x15, 0x2a, 0x2e, 0x63, 0x6d, 0x2e,
+ 0x73, 0x74, 0x65, 0x61, 0x6d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x65, 0x64,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+ 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
+ 0x00, 0xcd, 0x98, 0x0c, 0x13, 0xb2, 0xb9, 0xf2, 0xa5, 0xc6, 0x52, 0xad,
+ 0xf9, 0x4d, 0xcf, 0x1e, 0x2b, 0x74, 0x05, 0xd1, 0x2e, 0x95, 0xc3, 0x9d,
+ 0x9b, 0x03, 0x2a, 0xc6, 0x65, 0x1e, 0xda, 0x5d, 0x57, 0x3c, 0x61, 0xa1,
+ 0x3d, 0xa3, 0xe7, 0x0c, 0xdd, 0xb1, 0x6b, 0x30, 0x97, 0x99, 0xc7, 0x77,
+ 0xab, 0xc2, 0xb0, 0x0a, 0x5b, 0x1c, 0x86, 0x55, 0x42, 0x25, 0xa8, 0x4e,
+ 0xe2, 0x61, 0xfe, 0x88, 0x10, 0x25, 0xf5, 0x8e, 0x9c, 0x0f, 0xc7, 0xa5,
+ 0xef, 0x9d, 0xd5, 0xf0, 0x2a, 0xf2, 0x31, 0x59, 0x59, 0xfc, 0xe0, 0x1f,
+ 0x8f, 0xb4, 0xa1, 0x06, 0x32, 0x04, 0x37, 0x3d, 0x9d, 0xad, 0xc1, 0xe0,
+ 0x00, 0x3d, 0x8d, 0x60, 0x4c, 0x9e, 0x6a, 0x1f, 0xd2, 0xf6, 0xf8, 0x86,
+ 0x0b, 0x11, 0x7b, 0xfd, 0x75, 0xae, 0x20, 0x9b, 0xca, 0x52, 0x5f, 0x4e,
+ 0xad, 0x2e, 0xa2, 0xce, 0xed, 0x35, 0x08, 0x23, 0xa8, 0x6e, 0x61, 0x7e,
+ 0x18, 0x1a, 0x6a, 0xd9, 0xe0, 0x3b, 0x52, 0x64, 0xe9, 0x2c, 0x81, 0x8f,
+ 0xbc, 0x4b, 0x48, 0xd1, 0x7a, 0x3e, 0x02, 0x9c, 0xad, 0x87, 0x73, 0xae,
+ 0xaa, 0xea, 0x32, 0xfb, 0x07, 0x4e, 0xcb, 0xe9, 0xac, 0xac, 0x50, 0x0f,
+ 0x49, 0xb7, 0x23, 0x3b, 0x1f, 0xb2, 0x24, 0x46, 0x78, 0x32, 0x11, 0x9e,
+ 0xa2, 0xeb, 0xd8, 0x8b, 0x7e, 0x56, 0x92, 0xaa, 0x29, 0xbd, 0x55, 0xc8,
+ 0x3e, 0x69, 0xe2, 0x56, 0xf4, 0x24, 0x58, 0x7b, 0xf8, 0xb0, 0xbb, 0x72,
+ 0xb7, 0x38, 0x34, 0xe3, 0x0f, 0x30, 0xf4, 0xfd, 0x44, 0xf1, 0x53, 0x0f,
+ 0xc5, 0x31, 0xd6, 0xad, 0x45, 0xbf, 0x57, 0x2c, 0x4c, 0xe5, 0x1a, 0xc0,
+ 0x08, 0x25, 0x88, 0x2f, 0xca, 0x07, 0x2e, 0x35, 0x31, 0xa7, 0x40, 0x3a,
+ 0x71, 0x1d, 0xba, 0x09, 0xf8, 0x76, 0x6c, 0x69, 0xb2, 0x89, 0xd7, 0xbe,
+ 0xca, 0x9d, 0xf5, 0xd4, 0x7d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82,
+ 0x03, 0x87, 0x30, 0x82, 0x03, 0x83, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb7, 0x6b, 0xa2, 0xea, 0xa8,
+ 0xaa, 0x84, 0x8c, 0x79, 0xea, 0xb4, 0xda, 0x0f, 0x98, 0xb2, 0xc5, 0x95,
+ 0x76, 0xb9, 0xf4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
+ 0x04, 0x14, 0x22, 0x68, 0x57, 0xb9, 0xc0, 0x1f, 0xce, 0xa6, 0xbf, 0xb6,
+ 0x55, 0xcb, 0x2a, 0x1b, 0xe6, 0xe0, 0x76, 0x94, 0x07, 0x06, 0x30, 0x35,
+ 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x2e, 0x30, 0x2c, 0x82, 0x15, 0x2a,
+ 0x2e, 0x63, 0x6d, 0x2e, 0x73, 0x74, 0x65, 0x61, 0x6d, 0x70, 0x6f, 0x77,
+ 0x65, 0x72, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x13, 0x63, 0x6d,
+ 0x2e, 0x73, 0x74, 0x65, 0x61, 0x6d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x65,
+ 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
+ 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x1d, 0x06,
+ 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
+ 0x05, 0x07, 0x03, 0x02, 0x30, 0x81, 0x8b, 0x06, 0x03, 0x55, 0x1d, 0x1f,
+ 0x04, 0x81, 0x83, 0x30, 0x81, 0x80, 0x30, 0x3e, 0xa0, 0x3c, 0xa0, 0x3a,
+ 0x86, 0x38, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c,
+ 0x33, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x54,
+ 0x4c, 0x53, 0x52, 0x53, 0x41, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x32,
+ 0x30, 0x32, 0x30, 0x43, 0x41, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3e,
+ 0xa0, 0x3c, 0xa0, 0x3a, 0x86, 0x38, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x63, 0x72, 0x6c, 0x34, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65,
+ 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43,
+ 0x65, 0x72, 0x74, 0x54, 0x4c, 0x53, 0x52, 0x53, 0x41, 0x53, 0x48, 0x41,
+ 0x32, 0x35, 0x36, 0x32, 0x30, 0x32, 0x30, 0x43, 0x41, 0x31, 0x2e, 0x63,
+ 0x72, 0x6c, 0x30, 0x3e, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x37, 0x30,
+ 0x35, 0x30, 0x33, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x02, 0x30,
+ 0x29, 0x30, 0x27, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02,
+ 0x01, 0x16, 0x1b, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77,
+ 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x7d, 0x06, 0x08, 0x2b, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x71, 0x30, 0x6f, 0x30, 0x24,
+ 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18,
+ 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e,
+ 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x30, 0x47, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02,
+ 0x86, 0x3b, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x61, 0x63,
+ 0x65, 0x72, 0x74, 0x73, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72,
+ 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65,
+ 0x72, 0x74, 0x54, 0x4c, 0x53, 0x52, 0x53, 0x41, 0x53, 0x48, 0x41, 0x32,
+ 0x35, 0x36, 0x32, 0x30, 0x32, 0x30, 0x43, 0x41, 0x31, 0x2e, 0x63, 0x72,
+ 0x74, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+ 0x02, 0x30, 0x00, 0x30, 0x82, 0x01, 0x7e, 0x06, 0x0a, 0x2b, 0x06, 0x01,
+ 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x02, 0x04, 0x82, 0x01, 0x6e, 0x04,
+ 0x82, 0x01, 0x6a, 0x01, 0x68, 0x00, 0x76, 0x00, 0x29, 0x79, 0xbe, 0xf0,
+ 0x9e, 0x39, 0x39, 0x21, 0xf0, 0x56, 0x73, 0x9f, 0x63, 0xa5, 0x77, 0xe5,
+ 0xbe, 0x57, 0x7d, 0x9c, 0x60, 0x0a, 0xf8, 0xf9, 0x4d, 0x5d, 0x26, 0x5c,
+ 0x25, 0x5d, 0xc7, 0x84, 0x00, 0x00, 0x01, 0x79, 0x19, 0x43, 0x10, 0x65,
+ 0x00, 0x00, 0x04, 0x03, 0x00, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0x93,
+ 0x5f, 0x66, 0xe4, 0xfe, 0x76, 0x25, 0xe6, 0x07, 0x74, 0xa1, 0x8b, 0x7f,
+ 0x37, 0xad, 0xb1, 0x40, 0x8f, 0x20, 0x66, 0x71, 0x57, 0x14, 0x2c, 0x2e,
+ 0x28, 0xe0, 0xb2, 0x95, 0xd5, 0x19, 0xd0, 0x02, 0x20, 0x32, 0xd1, 0xa8,
+ 0x59, 0xfd, 0x69, 0x24, 0x8a, 0x27, 0x7e, 0x56, 0x06, 0xce, 0x6d, 0xeb,
+ 0xa1, 0xc6, 0x2a, 0xce, 0x4b, 0x37, 0xb1, 0x25, 0xca, 0x6d, 0xd3, 0x43,
+ 0xf3, 0xdb, 0xb8, 0xa5, 0x5e, 0x00, 0x76, 0x00, 0x22, 0x45, 0x45, 0x07,
+ 0x59, 0x55, 0x24, 0x56, 0x96, 0x3f, 0xa1, 0x2f, 0xf1, 0xf7, 0x6d, 0x86,
+ 0xe0, 0x23, 0x26, 0x63, 0xad, 0xc0, 0x4b, 0x7f, 0x5d, 0xc6, 0x83, 0x5c,
+ 0x6e, 0xe2, 0x0f, 0x02, 0x00, 0x00, 0x01, 0x79, 0x19, 0x43, 0x10, 0xa4,
+ 0x00, 0x00, 0x04, 0x03, 0x00, 0x47, 0x30, 0x45, 0x02, 0x20, 0x3a, 0x73,
+ 0x53, 0xfb, 0xbb, 0x42, 0xdf, 0x2e, 0xa2, 0xc0, 0xc5, 0x29, 0x57, 0xda,
+ 0xb9, 0x0b, 0x76, 0x58, 0xb6, 0xeb, 0xd3, 0x4d, 0x10, 0x95, 0x1b, 0x58,
+ 0x3e, 0x58, 0x86, 0xea, 0xec, 0xe5, 0x02, 0x21, 0x00, 0xeb, 0xb2, 0xfe,
+ 0x83, 0x74, 0xdf, 0xb5, 0xfd, 0x8f, 0x74, 0x82, 0xd3, 0x8f, 0x6b, 0xce,
+ 0x63, 0x8b, 0x93, 0x94, 0x08, 0x7b, 0x1c, 0x6b, 0x48, 0xae, 0x59, 0xa1,
+ 0x7e, 0xec, 0x59, 0xdf, 0x56, 0x00, 0x76, 0x00, 0x51, 0xa3, 0xb0, 0xf5,
+ 0xfd, 0x01, 0x79, 0x9c, 0x56, 0x6d, 0xb8, 0x37, 0x78, 0x8f, 0x0c, 0xa4,
+ 0x7a, 0xcc, 0x1b, 0x27, 0xcb, 0xf7, 0x9e, 0x88, 0x42, 0x9a, 0x0d, 0xfe,
+ 0xd4, 0x8b, 0x05, 0xe5, 0x00, 0x00, 0x01, 0x79, 0x19, 0x43, 0x10, 0xea,
+ 0x00, 0x00, 0x04, 0x03, 0x00, 0x47, 0x30, 0x45, 0x02, 0x20, 0x68, 0x89,
+ 0x8b, 0xab, 0x98, 0xd3, 0x4f, 0x41, 0x4f, 0x7d, 0x1c, 0x52, 0xbe, 0x1b,
+ 0xf1, 0xbe, 0xb3, 0x68, 0x49, 0x5a, 0x91, 0x93, 0xdc, 0xac, 0xba, 0x6e,
+ 0x58, 0x8d, 0xcd, 0x3c, 0x5a, 0x26, 0x02, 0x21, 0x00, 0x85, 0x09, 0xf7,
+ 0x21, 0x4a, 0x66, 0x45, 0x77, 0xfe, 0xd5, 0x77, 0x25, 0xd5, 0xc5, 0x1a,
+ 0xb3, 0x33, 0xd8, 0x86, 0x52, 0xcc, 0xe1, 0x26, 0x21, 0x03, 0xcf, 0x1b,
+ 0x34, 0x24, 0xab, 0xc0, 0x1f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
+ 0x00, 0xbd, 0x22, 0x40, 0xf1, 0x6d, 0xe7, 0x68, 0x89, 0x82, 0x53, 0xcd,
+ 0x64, 0xed, 0x21, 0x17, 0x90, 0x3a, 0xd0, 0xa3, 0x21, 0x42, 0x40, 0x60,
+ 0xf2, 0x2c, 0xf7, 0x40, 0xef, 0xc3, 0xf0, 0x22, 0x24, 0xc2, 0x51, 0x17,
+ 0x9d, 0x4b, 0x10, 0x9f, 0x86, 0x1a, 0x05, 0x4c, 0x6a, 0xe0, 0x13, 0xbb,
+ 0x29, 0xad, 0xf7, 0x18, 0x5f, 0x76, 0x01, 0x10, 0x8b, 0x1c, 0x29, 0x79,
+ 0x23, 0x94, 0x58, 0x1a, 0xa6, 0xf8, 0xac, 0x9b, 0x2e, 0xe0, 0x70, 0x1d,
+ 0x06, 0x1a, 0xe9, 0x5d, 0x24, 0x9f, 0x03, 0xff, 0x40, 0xe5, 0xc1, 0xb0,
+ 0xb9, 0xa7, 0x7e, 0x19, 0x3d, 0x0c, 0x99, 0x89, 0x81, 0xe4, 0x53, 0x9b,
+ 0xbd, 0x66, 0x1b, 0xba, 0x2e, 0xcd, 0xff, 0x24, 0x16, 0xd2, 0x89, 0xc9,
+ 0x75, 0xdd, 0xc9, 0x78, 0x25, 0x1e, 0x11, 0x43, 0x25, 0x06, 0x15, 0xe5,
+ 0xe3, 0x6b, 0xf9, 0x33, 0xee, 0x06, 0x16, 0x92, 0x8e, 0xe1, 0x8a, 0x93,
+ 0x41, 0x15, 0x8b, 0xf1, 0x06, 0xf7, 0x52, 0x07, 0x25, 0xb8, 0x6a, 0xae,
+ 0x46, 0x70, 0xa6, 0x81, 0x74, 0x70, 0x3c, 0x50, 0x42, 0x85, 0x65, 0x41,
+ 0xdb, 0x25, 0xb3, 0x4f, 0xce, 0x25, 0xb5, 0x2b, 0x62, 0xb7, 0x2b, 0xbf,
+ 0x66, 0xc4, 0xb4, 0x8a, 0x10, 0xb0, 0x50, 0x8e, 0x84, 0xf8, 0xe5, 0x28,
+ 0x86, 0xda, 0x7d, 0xe6, 0x65, 0xbf, 0xb1, 0xd5, 0x7d, 0x09, 0x28, 0x61,
+ 0xa3, 0x14, 0x89, 0x23, 0x35, 0x6e, 0x9c, 0x70, 0x06, 0x8b, 0xcb, 0x84,
+ 0xe8, 0x70, 0x8d, 0xb9, 0xfb, 0x74, 0xcf, 0x77, 0x63, 0x00, 0x5d, 0x8c,
+ 0xbb, 0x62, 0x4a, 0x2b, 0xc2, 0x8b, 0x2c, 0xd9, 0x9a, 0xa8, 0x83, 0x6f,
+ 0x06, 0x2a, 0x2a, 0x30, 0x4c, 0x39, 0xb4, 0xf8, 0x7d, 0x8c, 0x5e, 0xa7,
+ 0xcb, 0xce, 0x64, 0xe0, 0x27, 0xfa, 0x24, 0x42, 0xdd, 0xd1, 0x1d, 0xf8,
+ 0xa9, 0xd7, 0xc4, 0x0c, 0x92
+};
+
+static const BYTE ocsp_cert_issuer[] = {
+ 0x30, 0x82, 0x04, 0xbe, 0x30, 0x82, 0x03, 0xa6, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x10, 0x06, 0xd8, 0xd9, 0x04, 0xd5, 0x58, 0x43, 0x46, 0xf6,
+ 0x8a, 0x2f, 0xa7, 0x54, 0x22, 0x7e, 0xc4, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x61,
+ 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+ 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c,
+ 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63,
+ 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77,
+ 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47,
+ 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
+ 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x34, 0x31, 0x34, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x30, 0x34,
+ 0x31, 0x33, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x4f, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
+ 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44,
+ 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31,
+ 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x20, 0x44, 0x69,
+ 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x54, 0x4c, 0x53, 0x20, 0x52,
+ 0x53, 0x41, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x32, 0x30,
+ 0x32, 0x30, 0x20, 0x43, 0x41, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+ 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
+ 0x01, 0x01, 0x00, 0xc1, 0x4b, 0xb3, 0x65, 0x47, 0x70, 0xbc, 0xdd, 0x4f,
+ 0x58, 0xdb, 0xec, 0x9c, 0xed, 0xc3, 0x66, 0xe5, 0x1f, 0x31, 0x13, 0x54,
+ 0xad, 0x4a, 0x66, 0x46, 0x1f, 0x2c, 0x0a, 0xec, 0x64, 0x07, 0xe5, 0x2e,
+ 0xdc, 0xdc, 0xb9, 0x0a, 0x20, 0xed, 0xdf, 0xe3, 0xc4, 0xd0, 0x9e, 0x9a,
+ 0xa9, 0x7a, 0x1d, 0x82, 0x88, 0xe5, 0x11, 0x56, 0xdb, 0x1e, 0x9f, 0x58,
+ 0xc2, 0x51, 0xe7, 0x2c, 0x34, 0x0d, 0x2e, 0xd2, 0x92, 0xe1, 0x56, 0xcb,
+ 0xf1, 0x79, 0x5f, 0xb3, 0xbb, 0x87, 0xca, 0x25, 0x03, 0x7b, 0x9a, 0x52,
+ 0x41, 0x66, 0x10, 0x60, 0x4f, 0x57, 0x13, 0x49, 0xf0, 0xe8, 0x37, 0x67,
+ 0x83, 0xdf, 0xe7, 0xd3, 0x4b, 0x67, 0x4c, 0x22, 0x51, 0xa6, 0xdf, 0x0e,
+ 0x99, 0x10, 0xed, 0x57, 0x51, 0x74, 0x26, 0xe2, 0x7d, 0xc7, 0xca, 0x62,
+ 0x2e, 0x13, 0x1b, 0x7f, 0x23, 0x88, 0x25, 0x53, 0x6f, 0xc1, 0x34, 0x58,
+ 0x00, 0x8b, 0x84, 0xff, 0xf8, 0xbe, 0xa7, 0x58, 0x49, 0x22, 0x7b, 0x96,
+ 0xad, 0xa2, 0x88, 0x9b, 0x15, 0xbc, 0xa0, 0x7c, 0xdf, 0xe9, 0x51, 0xa8,
+ 0xd5, 0xb0, 0xed, 0x37, 0xe2, 0x36, 0xb4, 0x82, 0x4b, 0x62, 0xb5, 0x49,
+ 0x9a, 0xec, 0xc7, 0x67, 0xd6, 0xe3, 0x3e, 0xf5, 0xe3, 0xd6, 0x12, 0x5e,
+ 0x44, 0xf1, 0xbf, 0x71, 0x42, 0x7d, 0x58, 0x84, 0x03, 0x80, 0xb1, 0x81,
+ 0x01, 0xfa, 0xf9, 0xca, 0x32, 0xbb, 0xb4, 0x8e, 0x27, 0x87, 0x27, 0xc5,
+ 0x2b, 0x74, 0xd4, 0xa8, 0xd6, 0x97, 0xde, 0xc3, 0x64, 0xf9, 0xca, 0xce,
+ 0x53, 0xa2, 0x56, 0xbc, 0x78, 0x17, 0x8e, 0x49, 0x03, 0x29, 0xae, 0xfb,
+ 0x49, 0x4f, 0xa4, 0x15, 0xb9, 0xce, 0xf2, 0x5c, 0x19, 0x57, 0x6d, 0x6b,
+ 0x79, 0xa7, 0x2b, 0xa2, 0x27, 0x20, 0x13, 0xb5, 0xd0, 0x3d, 0x40, 0xd3,
+ 0x21, 0x30, 0x07, 0x93, 0xea, 0x99, 0xf5, 0x02, 0x03, 0x01, 0x00, 0x01,
+ 0xa3, 0x82, 0x01, 0x82, 0x30, 0x82, 0x01, 0x7e, 0x30, 0x12, 0x06, 0x03,
+ 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01,
+ 0xff, 0x02, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+ 0x16, 0x04, 0x14, 0xb7, 0x6b, 0xa2, 0xea, 0xa8, 0xaa, 0x84, 0x8c, 0x79,
+ 0xea, 0xb4, 0xda, 0x0f, 0x98, 0xb2, 0xc5, 0x95, 0x76, 0xb9, 0xf4, 0x30,
+ 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+ 0x03, 0xde, 0x50, 0x35, 0x56, 0xd1, 0x4c, 0xbb, 0x66, 0xf0, 0xa3, 0xe2,
+ 0x1b, 0x1b, 0xc3, 0x97, 0xb2, 0x3d, 0xd1, 0x55, 0x30, 0x0e, 0x06, 0x03,
+ 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86,
+ 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06,
+ 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x76, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x6a, 0x30, 0x68, 0x30,
+ 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86,
+ 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70,
+ 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x30, 0x40, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30,
+ 0x02, 0x86, 0x34, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x61,
+ 0x63, 0x65, 0x72, 0x74, 0x73, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65,
+ 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43,
+ 0x65, 0x72, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f,
+ 0x74, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x42, 0x06, 0x03, 0x55,
+ 0x1d, 0x1f, 0x04, 0x3b, 0x30, 0x39, 0x30, 0x37, 0xa0, 0x35, 0xa0, 0x33,
+ 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c,
+ 0x33, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x47,
+ 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2e,
+ 0x63, 0x72, 0x6c, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x36,
+ 0x30, 0x34, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd,
+ 0x6c, 0x02, 0x01, 0x30, 0x07, 0x06, 0x05, 0x67, 0x81, 0x0c, 0x01, 0x01,
+ 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x01, 0x30, 0x08,
+ 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x02, 0x30, 0x08, 0x06, 0x06,
+ 0x67, 0x81, 0x0c, 0x01, 0x02, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01,
+ 0x01, 0x00, 0x80, 0x32, 0xce, 0x5e, 0x0b, 0xdd, 0x6e, 0x5a, 0x0d, 0x0a,
+ 0xaf, 0xe1, 0xd6, 0x84, 0xcb, 0xc0, 0x8e, 0xfa, 0x85, 0x70, 0xed, 0xda,
+ 0x5d, 0xb3, 0x0c, 0xf7, 0x2b, 0x75, 0x40, 0xfe, 0x85, 0x0a, 0xfa, 0xf3,
+ 0x31, 0x78, 0xb7, 0x70, 0x4b, 0x1a, 0x89, 0x58, 0xba, 0x80, 0xbd, 0xf3,
+ 0x6b, 0x1d, 0xe9, 0x7e, 0xcf, 0x0b, 0xba, 0x58, 0x9c, 0x59, 0xd4, 0x90,
+ 0xd3, 0xfd, 0x6c, 0xfd, 0xd0, 0x98, 0x6d, 0xb7, 0x71, 0x82, 0x5b, 0xcf,
+ 0x6d, 0x0b, 0x5a, 0x09, 0xd0, 0x7b, 0xde, 0xc4, 0x43, 0xd8, 0x2a, 0xa4,
+ 0xde, 0x9e, 0x41, 0x26, 0x5f, 0xbb, 0x8f, 0x99, 0xcb, 0xdd, 0xae, 0xe1,
+ 0xa8, 0x6f, 0x9f, 0x87, 0xfe, 0x74, 0xb7, 0x1f, 0x1b, 0x20, 0xab, 0xb1,
+ 0x4f, 0xc6, 0xf5, 0x67, 0x5d, 0x5d, 0x9b, 0x3c, 0xe9, 0xff, 0x69, 0xf7,
+ 0x61, 0x6c, 0xd6, 0xd9, 0xf3, 0xfd, 0x36, 0xc6, 0xab, 0x03, 0x88, 0x76,
+ 0xd2, 0x4b, 0x2e, 0x75, 0x86, 0xe3, 0xfc, 0xd8, 0x55, 0x7d, 0x26, 0xc2,
+ 0x11, 0x77, 0xdf, 0x3e, 0x02, 0xb6, 0x7c, 0xf3, 0xab, 0x7b, 0x7a, 0x86,
+ 0x36, 0x6f, 0xb8, 0xf7, 0xd8, 0x93, 0x71, 0xcf, 0x86, 0xdf, 0x73, 0x30,
+ 0xfa, 0x7b, 0xab, 0xed, 0x2a, 0x59, 0xc8, 0x42, 0x84, 0x3b, 0x11, 0x17,
+ 0x1a, 0x52, 0xf3, 0xc9, 0x0e, 0x14, 0x7d, 0xa2, 0x5b, 0x72, 0x67, 0xba,
+ 0x71, 0xed, 0x57, 0x47, 0x66, 0xc5, 0xb8, 0x02, 0x4a, 0x65, 0x34, 0x5e,
+ 0x8b, 0xd0, 0x2a, 0x3c, 0x20, 0x9c, 0x51, 0x99, 0x4c, 0xe7, 0x52, 0x9e,
+ 0xf7, 0x6b, 0x11, 0x2b, 0x0d, 0x92, 0x7e, 0x1d, 0xe8, 0x8a, 0xeb, 0x36,
+ 0x16, 0x43, 0x87, 0xea, 0x2a, 0x63, 0xbf, 0x75, 0x3f, 0xeb, 0xde, 0xc4,
+ 0x03, 0xbb, 0x0a, 0x3c, 0xf7, 0x30, 0xef, 0xeb, 0xaf, 0x4c, 0xfc, 0x8b,
+ 0x36, 0x10, 0x73, 0x3e, 0xf3, 0xa4
+};
+
+static const BYTE ocsp_cert_revoked[] = {
+ 0x30, 0x82, 0x06, 0x86, 0x30, 0x82, 0x05, 0x6e, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x10, 0x0d, 0x2e, 0x67, 0xa2, 0x98, 0x85, 0x3b, 0x9a, 0x54,
+ 0x52, 0xe3, 0xa2, 0x85, 0xa4, 0x57, 0x2f, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x59,
+ 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+ 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c,
+ 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63,
+ 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2a, 0x52,
+ 0x61, 0x70, 0x69, 0x64, 0x53, 0x53, 0x4c, 0x20, 0x54, 0x4c, 0x53, 0x20,
+ 0x44, 0x56, 0x20, 0x52, 0x53, 0x41, 0x20, 0x4d, 0x69, 0x78, 0x65, 0x64,
+ 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x32, 0x30, 0x32, 0x30,
+ 0x20, 0x43, 0x41, 0x2d, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x31,
+ 0x30, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d,
+ 0x32, 0x32, 0x31, 0x30, 0x32, 0x37, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39,
+ 0x5a, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x12, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x2e, 0x62, 0x61,
+ 0x64, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xb0, 0x76, 0x2d, 0x55, 0x66, 0xdc, 0x72,
+ 0x8a, 0xa0, 0x9e, 0x85, 0x92, 0x38, 0x7f, 0x5b, 0xe1, 0x93, 0x8d, 0xad,
+ 0x06, 0xc8, 0xad, 0xe9, 0x89, 0xb4, 0xef, 0x1e, 0x77, 0x5b, 0x33, 0x45,
+ 0x16, 0x60, 0x7d, 0x33, 0x38, 0x68, 0x04, 0xd7, 0xc9, 0x83, 0x42, 0x83,
+ 0xd9, 0x30, 0x4b, 0x54, 0x49, 0x14, 0xca, 0xed, 0xbe, 0x0c, 0x76, 0xba,
+ 0x5f, 0xa6, 0x5c, 0x33, 0x78, 0x3f, 0x39, 0xf2, 0x49, 0xa8, 0x88, 0x32,
+ 0xee, 0x53, 0x21, 0x14, 0xd3, 0xaa, 0x5c, 0x58, 0x3c, 0x39, 0xcc, 0xf7,
+ 0x80, 0xb1, 0x27, 0x1f, 0x54, 0x79, 0x7b, 0x6c, 0x8b, 0xff, 0x41, 0xaa,
+ 0x39, 0x24, 0x95, 0x5f, 0x71, 0xbc, 0x49, 0xbf, 0x39, 0x3b, 0xa5, 0xd5,
+ 0xe1, 0xa5, 0xde, 0x1d, 0x40, 0x81, 0x25, 0xdc, 0x8a, 0x47, 0x82, 0xfe,
+ 0xcd, 0x7c, 0x4b, 0x2c, 0x04, 0xbb, 0xd3, 0x27, 0x56, 0x51, 0xa0, 0x61,
+ 0xf2, 0xd2, 0xcb, 0x55, 0x08, 0x25, 0x2a, 0x85, 0xdb, 0x2c, 0x06, 0x8d,
+ 0x0d, 0x61, 0xc2, 0x5b, 0x3e, 0x9b, 0x46, 0xdc, 0x58, 0xff, 0x13, 0x27,
+ 0xbe, 0x0a, 0x44, 0x1e, 0x68, 0xfe, 0xe1, 0xf6, 0xb7, 0xde, 0x9f, 0x8e,
+ 0x6c, 0xc4, 0xb5, 0x19, 0xfa, 0xd7, 0xd3, 0x4f, 0x55, 0xa8, 0x61, 0x79,
+ 0xdb, 0x61, 0x2f, 0x6a, 0x9c, 0x2c, 0xf1, 0xc4, 0x81, 0xbb, 0x9e, 0xd2,
+ 0x02, 0x05, 0xba, 0x9c, 0x14, 0xa0, 0xf9, 0xf3, 0x54, 0x79, 0x7d, 0x69,
+ 0xd9, 0xba, 0x66, 0x1c, 0x87, 0x95, 0x41, 0x50, 0x0e, 0xf9, 0x5e, 0xe1,
+ 0xb7, 0xbd, 0xf5, 0x31, 0x24, 0xc5, 0x21, 0x21, 0x03, 0x8a, 0xcf, 0x6d,
+ 0x78, 0x58, 0xde, 0xd9, 0x30, 0x7d, 0x03, 0x42, 0x52, 0xd6, 0xb0, 0x1b,
+ 0xb9, 0xc9, 0x54, 0x1b, 0x5a, 0xe8, 0xc8, 0x53, 0xf0, 0xac, 0x2b, 0x82,
+ 0x10, 0x27, 0xa6, 0xa9, 0x70, 0x25, 0xae, 0xf8, 0xa7, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0xa3, 0x82, 0x03, 0x84, 0x30, 0x82, 0x03, 0x80, 0x30, 0x1f,
+ 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xa4,
+ 0x8d, 0xe5, 0xbe, 0x7c, 0x79, 0xe4, 0x70, 0x23, 0x6d, 0x2e, 0x29, 0x34,
+ 0xad, 0x23, 0x58, 0xdc, 0xf5, 0x31, 0x7f, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb0, 0xc8, 0xce, 0x20, 0xb2, 0x78,
+ 0xcc, 0x1d, 0x23, 0xef, 0xf0, 0xfe, 0xd6, 0x0e, 0x29, 0x4b, 0xac, 0x15,
+ 0x72, 0x3c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x16, 0x30,
+ 0x14, 0x82, 0x12, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x2e, 0x62,
+ 0x61, 0x64, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0e, 0x06,
+ 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05,
+ 0xa0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14,
+ 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x81, 0x9b, 0x06,
+ 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x81, 0x93, 0x30, 0x81, 0x90, 0x30, 0x46,
+ 0xa0, 0x44, 0xa0, 0x42, 0x86, 0x40, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x63, 0x72, 0x6c, 0x33, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65,
+ 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x52, 0x61, 0x70, 0x69, 0x64,
+ 0x53, 0x53, 0x4c, 0x54, 0x4c, 0x53, 0x44, 0x56, 0x52, 0x53, 0x41, 0x4d,
+ 0x69, 0x78, 0x65, 0x64, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x32, 0x30,
+ 0x32, 0x30, 0x43, 0x41, 0x2d, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x46,
+ 0xa0, 0x44, 0xa0, 0x42, 0x86, 0x40, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x63, 0x72, 0x6c, 0x34, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65,
+ 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x52, 0x61, 0x70, 0x69, 0x64,
+ 0x53, 0x53, 0x4c, 0x54, 0x4c, 0x53, 0x44, 0x56, 0x52, 0x53, 0x41, 0x4d,
+ 0x69, 0x78, 0x65, 0x64, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x32, 0x30,
+ 0x32, 0x30, 0x43, 0x41, 0x2d, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3e,
+ 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x37, 0x30, 0x35, 0x30, 0x33, 0x06,
+ 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x01, 0x30, 0x29, 0x30, 0x27, 0x06,
+ 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1b, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69,
+ 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43,
+ 0x50, 0x53, 0x30, 0x81, 0x85, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+ 0x07, 0x01, 0x01, 0x04, 0x79, 0x30, 0x77, 0x30, 0x24, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, 0x67,
+ 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4f, 0x06,
+ 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x43, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74,
+ 0x73, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x52, 0x61, 0x70, 0x69, 0x64, 0x53, 0x53, 0x4c, 0x54,
+ 0x4c, 0x53, 0x44, 0x56, 0x52, 0x53, 0x41, 0x4d, 0x69, 0x78, 0x65, 0x64,
+ 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x32, 0x30, 0x32, 0x30, 0x43, 0x41,
+ 0x2d, 0x31, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d,
+ 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x82, 0x01, 0x7d, 0x06, 0x0a, 0x2b,
+ 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x02, 0x04, 0x82, 0x01,
+ 0x6d, 0x04, 0x82, 0x01, 0x69, 0x01, 0x67, 0x00, 0x76, 0x00, 0x29, 0x79,
+ 0xbe, 0xf0, 0x9e, 0x39, 0x39, 0x21, 0xf0, 0x56, 0x73, 0x9f, 0x63, 0xa5,
+ 0x77, 0xe5, 0xbe, 0x57, 0x7d, 0x9c, 0x60, 0x0a, 0xf8, 0xf9, 0x4d, 0x5d,
+ 0x26, 0x5c, 0x25, 0x5d, 0xc7, 0x84, 0x00, 0x00, 0x01, 0x7c, 0xc3, 0xa4,
+ 0xf7, 0x37, 0x00, 0x00, 0x04, 0x03, 0x00, 0x47, 0x30, 0x45, 0x02, 0x20,
+ 0x77, 0xb0, 0x79, 0x18, 0xf3, 0xde, 0x34, 0x70, 0xfa, 0xf2, 0x1b, 0xc2,
+ 0x32, 0x39, 0xc8, 0xc8, 0x95, 0xb0, 0xc8, 0x7a, 0x8f, 0x62, 0x23, 0x58,
+ 0xdd, 0xad, 0xf9, 0x1b, 0xbe, 0x84, 0x95, 0xed, 0x02, 0x21, 0x00, 0xdd,
+ 0x25, 0x68, 0x47, 0xa3, 0x84, 0x5f, 0x95, 0xb1, 0xea, 0xe7, 0xbc, 0x0a,
+ 0x09, 0x92, 0xf9, 0x5a, 0x56, 0x72, 0x31, 0xec, 0x07, 0xd6, 0xc6, 0x97,
+ 0x4d, 0x4c, 0x7b, 0x90, 0x75, 0x64, 0xae, 0x00, 0x76, 0x00, 0x51, 0xa3,
+ 0xb0, 0xf5, 0xfd, 0x01, 0x79, 0x9c, 0x56, 0x6d, 0xb8, 0x37, 0x78, 0x8f,
+ 0x0c, 0xa4, 0x7a, 0xcc, 0x1b, 0x27, 0xcb, 0xf7, 0x9e, 0x88, 0x42, 0x9a,
+ 0x0d, 0xfe, 0xd4, 0x8b, 0x05, 0xe5, 0x00, 0x00, 0x01, 0x7c, 0xc3, 0xa4,
+ 0xf7, 0x64, 0x00, 0x00, 0x04, 0x03, 0x00, 0x47, 0x30, 0x45, 0x02, 0x20,
+ 0x4c, 0x22, 0xff, 0x65, 0x39, 0x6b, 0x7e, 0x7b, 0x15, 0x21, 0x79, 0x44,
+ 0xc2, 0xeb, 0xb8, 0x4c, 0x2a, 0xc9, 0xa5, 0xc7, 0xac, 0xce, 0x5f, 0x6a,
+ 0x5d, 0xe8, 0xb7, 0x24, 0xc5, 0x76, 0xec, 0x19, 0x02, 0x21, 0x00, 0x94,
+ 0x5e, 0x02, 0xee, 0x14, 0x60, 0x80, 0x96, 0xbc, 0x0e, 0x39, 0x16, 0x01,
+ 0xa8, 0x37, 0x9f, 0x15, 0xb9, 0xb9, 0xba, 0x0f, 0xa2, 0x0c, 0x5a, 0x17,
+ 0x90, 0xa5, 0xe1, 0x33, 0x36, 0x45, 0xf2, 0x00, 0x75, 0x00, 0x41, 0xc8,
+ 0xca, 0xb1, 0xdf, 0x22, 0x46, 0x4a, 0x10, 0xc6, 0xa1, 0x3a, 0x09, 0x42,
+ 0x87, 0x5e, 0x4e, 0x31, 0x8b, 0x1b, 0x03, 0xeb, 0xeb, 0x4b, 0xc7, 0x68,
+ 0xf0, 0x90, 0x62, 0x96, 0x06, 0xf6, 0x00, 0x00, 0x01, 0x7c, 0xc3, 0xa4,
+ 0xf6, 0xdf, 0x00, 0x00, 0x04, 0x03, 0x00, 0x46, 0x30, 0x44, 0x02, 0x20,
+ 0x68, 0x8a, 0x5f, 0x50, 0xb7, 0x76, 0xda, 0x7e, 0x34, 0x32, 0xa5, 0x77,
+ 0x02, 0xa6, 0xfa, 0xa7, 0x87, 0xbb, 0xdb, 0x41, 0x5c, 0x80, 0x40, 0x2c,
+ 0x05, 0xe5, 0x09, 0xdd, 0x3f, 0xcc, 0x6d, 0x9f, 0x02, 0x20, 0x7b, 0x1d,
+ 0x64, 0x48, 0x61, 0x19, 0x75, 0xb6, 0x37, 0xd1, 0x3c, 0x1e, 0x38, 0x78,
+ 0x86, 0x7a, 0xf2, 0x79, 0x14, 0x08, 0x42, 0xe8, 0xdd, 0x0f, 0xff, 0x38,
+ 0x3a, 0x3c, 0x36, 0xd9, 0xbf, 0xd9, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01,
+ 0x01, 0x00, 0xd5, 0x8c, 0xbd, 0xbe, 0xe4, 0xdc, 0x94, 0xa4, 0xb7, 0xf3,
+ 0x49, 0xaf, 0xc4, 0x99, 0x26, 0xda, 0x27, 0x68, 0xda, 0xe8, 0xb8, 0xc1,
+ 0xba, 0xc6, 0x30, 0xb6, 0x16, 0xaa, 0x50, 0xfe, 0xf4, 0x77, 0x07, 0xeb,
+ 0x99, 0xf2, 0xda, 0xdd, 0x77, 0x1d, 0x19, 0x82, 0xf7, 0x24, 0x2a, 0x3b,
+ 0xa0, 0x63, 0xe0, 0xdb, 0x09, 0xbe, 0x10, 0x7f, 0xc5, 0x1f, 0x81, 0xba,
+ 0xaf, 0x9e, 0x49, 0xce, 0x32, 0x30, 0x49, 0x17, 0x8f, 0x74, 0xc6, 0xd6,
+ 0xcd, 0x6a, 0xd8, 0x3b, 0x47, 0x7b, 0xf0, 0xe0, 0x0c, 0xbb, 0xc0, 0x8e,
+ 0x3a, 0x1d, 0xa3, 0x7f, 0x92, 0xac, 0x7e, 0x8d, 0xdc, 0xa4, 0xb5, 0x30,
+ 0x2a, 0x57, 0x13, 0x23, 0xa7, 0xee, 0x25, 0xc6, 0x37, 0xed, 0x48, 0xb2,
+ 0x4a, 0xd0, 0x01, 0xfc, 0x85, 0xe5, 0xc1, 0xe2, 0xe0, 0xdc, 0x8c, 0x61,
+ 0x74, 0xaa, 0xaf, 0x68, 0x28, 0x26, 0x45, 0x94, 0xa3, 0xb1, 0x4c, 0xc9,
+ 0x5c, 0xc7, 0x92, 0xa2, 0x6c, 0x4a, 0x80, 0x6f, 0xdd, 0x48, 0xfa, 0x4f,
+ 0x04, 0xb2, 0x4a, 0x73, 0x17, 0xf2, 0xf9, 0x1e, 0x8e, 0x5c, 0xe9, 0x23,
+ 0xec, 0x53, 0xff, 0x3e, 0xc7, 0x8a, 0xb6, 0x18, 0x89, 0xbc, 0x77, 0x45,
+ 0x67, 0x4b, 0x9a, 0x73, 0x75, 0x6b, 0x57, 0xc8, 0xc0, 0x6a, 0xcb, 0x84,
+ 0x1d, 0xf4, 0xed, 0xef, 0x70, 0x16, 0x77, 0x8e, 0xf3, 0x1a, 0x8e, 0xbb,
+ 0x95, 0xf3, 0xeb, 0xf8, 0x5a, 0xe4, 0xa9, 0xb1, 0xdf, 0x1d, 0x36, 0xab,
+ 0x0a, 0xdd, 0x91, 0xaf, 0x2d, 0x71, 0x3c, 0xab, 0x97, 0x18, 0x03, 0xdc,
+ 0x5c, 0x1a, 0xa9, 0xb1, 0xdb, 0xb6, 0x48, 0x40, 0xc7, 0x19, 0xa7, 0x81,
+ 0x14, 0x0b, 0x0d, 0xce, 0x38, 0x6f, 0xda, 0xcf, 0xce, 0x0f, 0x64, 0x13,
+ 0x28, 0xf3, 0x4d, 0x67, 0x1b, 0x2c, 0xd1, 0x16, 0x54, 0x19, 0x6f, 0xaa,
+ 0x08, 0x54, 0xa3, 0x4d, 0x67, 0x64
+};
+
+static const BYTE ocsp_cert_revoked_issuer[] = {
+ 0x30, 0x82, 0x05, 0x51, 0x30, 0x82, 0x04, 0x39, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x10, 0x07, 0x98, 0x36, 0x03, 0xad, 0xe3, 0x99, 0x08, 0x21,
+ 0x9c, 0xa0, 0x0c, 0x27, 0xbc, 0x8a, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x61,
+ 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+ 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c,
+ 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63,
+ 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77,
+ 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47,
+ 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
+ 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x37, 0x31, 0x36, 0x31,
+ 0x32, 0x32, 0x35, 0x32, 0x37, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x35,
+ 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x59, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
+ 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44,
+ 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31,
+ 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2a, 0x52, 0x61,
+ 0x70, 0x69, 0x64, 0x53, 0x53, 0x4c, 0x20, 0x54, 0x4c, 0x53, 0x20, 0x44,
+ 0x56, 0x20, 0x52, 0x53, 0x41, 0x20, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x20,
+ 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x32, 0x30, 0x32, 0x30, 0x20,
+ 0x43, 0x41, 0x2d, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+ 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
+ 0x00, 0xda, 0x6e, 0x43, 0x55, 0x55, 0x99, 0x7b, 0xd9, 0x95, 0xa2, 0x66,
+ 0xc4, 0x65, 0x58, 0xa2, 0xd0, 0x0c, 0x17, 0x3a, 0x00, 0xa6, 0x88, 0x5b,
+ 0x24, 0x07, 0x8d, 0xa7, 0x33, 0x7e, 0xe3, 0xd2, 0xdb, 0x82, 0x4a, 0xcc,
+ 0x2e, 0xfd, 0xad, 0x6e, 0x52, 0x08, 0xf0, 0x7e, 0x37, 0xbc, 0xde, 0xd4,
+ 0x16, 0xe9, 0xb1, 0x57, 0xb9, 0x49, 0x74, 0xfc, 0x0b, 0x3f, 0x6d, 0xaa,
+ 0x6b, 0x4b, 0x15, 0xf5, 0xcc, 0x02, 0xaf, 0xa4, 0x19, 0xa0, 0x61, 0x28,
+ 0x6d, 0xd6, 0xbe, 0xe2, 0x9b, 0x9f, 0x1b, 0x46, 0x92, 0x7c, 0x74, 0x02,
+ 0x42, 0x1b, 0xa5, 0x6a, 0xa2, 0xa9, 0x3d, 0xc6, 0x18, 0x38, 0xf8, 0xd3,
+ 0xc2, 0x0a, 0x89, 0x03, 0xce, 0x00, 0x15, 0x88, 0xfc, 0x97, 0xf2, 0x1e,
+ 0x43, 0xc9, 0xf4, 0xd5, 0x5c, 0x82, 0xba, 0xb3, 0x08, 0x1c, 0x0e, 0x3b,
+ 0xf2, 0xdb, 0x36, 0x1b, 0xa1, 0x86, 0xb4, 0x4c, 0x74, 0xb9, 0xc9, 0xc4,
+ 0x7d, 0x5d, 0x90, 0x1d, 0x42, 0xfa, 0xe0, 0x40, 0xb6, 0xca, 0x1e, 0xf2,
+ 0x6d, 0xba, 0x28, 0xe6, 0xff, 0x27, 0x15, 0x65, 0x78, 0x97, 0x1f, 0xf1,
+ 0x71, 0xfc, 0x68, 0xc6, 0x41, 0x53, 0x56, 0x70, 0x08, 0x46, 0x01, 0xeb,
+ 0x1f, 0x6b, 0xd4, 0x74, 0xe8, 0x95, 0xf6, 0xc9, 0x4e, 0x8b, 0x1d, 0xf3,
+ 0xe4, 0xa3, 0xec, 0xda, 0xb2, 0xb6, 0x6d, 0xb6, 0x9c, 0x87, 0xc4, 0xa1,
+ 0xe4, 0x64, 0xa4, 0x82, 0x9d, 0x87, 0x46, 0x84, 0xbf, 0x9b, 0x2d, 0x2d,
+ 0x0a, 0xad, 0x6f, 0x8f, 0x22, 0xc9, 0x78, 0xfd, 0x1a, 0x37, 0x03, 0xdd,
+ 0xde, 0xb9, 0x39, 0x3b, 0xc2, 0xe2, 0x7d, 0xf2, 0xde, 0xbf, 0xd8, 0xfe,
+ 0x50, 0xa6, 0x68, 0xd2, 0xdb, 0x74, 0x56, 0xf4, 0xcb, 0x91, 0xd1, 0xa6,
+ 0x48, 0xde, 0x21, 0xd6, 0x65, 0x58, 0xe8, 0x39, 0xc6, 0x7c, 0xec, 0x29,
+ 0xd4, 0x2e, 0x52, 0x2b, 0x43, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82,
+ 0x02, 0x0b, 0x30, 0x82, 0x02, 0x07, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa4, 0x8d, 0xe5, 0xbe, 0x7c, 0x79, 0xe4,
+ 0x70, 0x23, 0x6d, 0x2e, 0x29, 0x34, 0xad, 0x23, 0x58, 0xdc, 0xf5, 0x31,
+ 0x7f, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x03, 0xde, 0x50, 0x35, 0x56, 0xd1, 0x4c, 0xbb, 0x66, 0xf0,
+ 0xa3, 0xe2, 0x1b, 0x1b, 0xc3, 0x97, 0xb2, 0x3d, 0xd1, 0x55, 0x30, 0x0e,
+ 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
+ 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30,
+ 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06,
+ 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x12, 0x06,
+ 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01,
+ 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01,
+ 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06,
+ 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64,
+ 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
+ 0x7b, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, 0x37,
+ 0xa0, 0x35, 0xa0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x63, 0x72, 0x6c, 0x33, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65,
+ 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43,
+ 0x65, 0x72, 0x74, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f,
+ 0x74, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x37, 0xa0, 0x35, 0xa0,
+ 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72,
+ 0x6c, 0x34, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74,
+ 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41,
+ 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x81, 0xce, 0x06, 0x03, 0x55, 0x1d, 0x20,
+ 0x04, 0x81, 0xc6, 0x30, 0x81, 0xc3, 0x30, 0x81, 0xc0, 0x06, 0x04, 0x55,
+ 0x1d, 0x20, 0x00, 0x30, 0x81, 0xb7, 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, 0x70,
+ 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69,
+ 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53,
+ 0x30, 0x81, 0x8a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02,
+ 0x02, 0x30, 0x7e, 0x0c, 0x7c, 0x41, 0x6e, 0x79, 0x20, 0x75, 0x73, 0x65,
+ 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x43, 0x65, 0x72,
+ 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x63, 0x6f, 0x6e,
+ 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x73, 0x20, 0x61, 0x63, 0x63,
+ 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x52, 0x65, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x50,
+ 0x61, 0x72, 0x74, 0x79, 0x20, 0x41, 0x67, 0x72, 0x65, 0x65, 0x6d, 0x65,
+ 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x61,
+ 0x74, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77,
+ 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x72, 0x70, 0x61, 0x2d, 0x75, 0x61, 0x30, 0x0d, 0x06,
+ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+ 0x03, 0x82, 0x01, 0x01, 0x00, 0x22, 0xe3, 0xdc, 0x6d, 0x48, 0xeb, 0x8e,
+ 0xca, 0x00, 0x72, 0x73, 0x2e, 0x74, 0xaa, 0xe0, 0x93, 0x84, 0x6e, 0x39,
+ 0xc4, 0x87, 0x54, 0x02, 0xc4, 0x02, 0x69, 0x71, 0x55, 0x45, 0xaf, 0x5a,
+ 0xb0, 0xf6, 0x81, 0xfe, 0x32, 0xc8, 0x35, 0x72, 0x4b, 0xde, 0xa5, 0x7d,
+ 0x27, 0x41, 0xa1, 0xd9, 0xb6, 0x4c, 0xd2, 0x4e, 0x32, 0x38, 0xc7, 0x80,
+ 0x31, 0x9e, 0x7b, 0xb2, 0x63, 0xfa, 0x26, 0x47, 0x09, 0x8a, 0x18, 0x4e,
+ 0x16, 0x57, 0xd0, 0x6b, 0x5f, 0x1a, 0x96, 0x37, 0x7e, 0xc4, 0xd7, 0x3a,
+ 0x6f, 0xe1, 0x97, 0xea, 0x81, 0x5c, 0x08, 0x71, 0xab, 0xfa, 0x0b, 0x04,
+ 0xc8, 0xf3, 0x3c, 0xaa, 0xf9, 0x4a, 0x1b, 0x17, 0x39, 0x4f, 0x97, 0x87,
+ 0x57, 0x35, 0x7a, 0x8e, 0x98, 0xe9, 0xcb, 0x39, 0x7a, 0x54, 0x42, 0xa9,
+ 0x6b, 0x11, 0xfa, 0x81, 0xd1, 0x95, 0xa5, 0x05, 0x60, 0x8e, 0x43, 0x91,
+ 0xf7, 0x26, 0x3d, 0x5c, 0x05, 0x25, 0x16, 0x7c, 0xe5, 0x38, 0x2a, 0x6a,
+ 0xb2, 0x6e, 0xeb, 0xd9, 0x95, 0x0a, 0xa4, 0x37, 0xeb, 0x85, 0x49, 0xd5,
+ 0xcd, 0x7d, 0xa7, 0x48, 0xcd, 0x79, 0x5d, 0x28, 0xf8, 0xf2, 0xb5, 0x41,
+ 0x04, 0x09, 0xc6, 0x25, 0x69, 0x0b, 0x3e, 0x28, 0xe5, 0x00, 0x27, 0x77,
+ 0xb1, 0x61, 0x4c, 0x55, 0x48, 0x8a, 0x47, 0x3d, 0x42, 0xe4, 0xf6, 0x72,
+ 0x7a, 0x5d, 0xa5, 0xec, 0x9f, 0xd6, 0xe1, 0xdf, 0x7d, 0x28, 0x52, 0xd2,
+ 0x62, 0x0a, 0x32, 0xe4, 0x60, 0xe6, 0x01, 0x1a, 0x70, 0x2d, 0xcf, 0xff,
+ 0x7d, 0x77, 0xe4, 0xaf, 0x8d, 0x27, 0x31, 0x8f, 0x22, 0x6c, 0x29, 0xb1,
+ 0x0a, 0xc8, 0xd7, 0x41, 0x37, 0xb4, 0x7c, 0x96, 0xed, 0xae, 0xb2, 0xcb,
+ 0xc9, 0x64, 0x25, 0x93, 0xd5, 0x43, 0x57, 0x6f, 0x7a, 0x10, 0x8f, 0xe4,
+ 0x40, 0xe2, 0x4d, 0x2d, 0x51, 0x24, 0x27, 0x9e, 0x0f
+};
+
static void testVerifyRevocation(void)
{
BOOL ret;
@@ -3643,6 +4157,44 @@ static void testVerifyRevocation(void)
CertCloseStore(revPara.hCrlStore, 0);
CertFreeCertificateContext(certs[1]);
CertFreeCertificateContext(certs[0]);
+
+ /* OCSP */
+ certs[0] = CertCreateCertificateContext(X509_ASN_ENCODING, ocsp_cert, sizeof(ocsp_cert));
+ memset(&revPara, 0, sizeof(revPara));
+ revPara.cbSize = sizeof(revPara);
+ memset(&status, 0x55, sizeof(status));
+ status.cbSize = sizeof(status);
+ SetLastError(0xdeadbeef);
+ ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, 1, (void **)&certs[0],
+ 0, &revPara, &status);
+ ok(!ret, "success\n");
+ ok(GetLastError() == CRYPT_E_REVOCATION_OFFLINE, "got %08lx\n", GetLastError());
+
+ revPara.pIssuerCert = CertCreateCertificateContext(X509_ASN_ENCODING, ocsp_cert_issuer,
+ sizeof(ocsp_cert_issuer));
+ ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, 1, (void **)&certs[0],
+ 0, &revPara, &status);
+ ok(ret, "got %08lx\n", GetLastError());
+ ok(!status.dwError, "got %08lx\n", status.dwError);
+ ok(!status.dwIndex, "got %ld\n", status.dwIndex);
+ CertFreeCertificateContext(revPara.pIssuerCert);
+ CertFreeCertificateContext(certs[0]);
+
+ certs[0] = CertCreateCertificateContext(X509_ASN_ENCODING, ocsp_cert_revoked, sizeof(ocsp_cert_revoked));
+ revPara.pIssuerCert = CertCreateCertificateContext(X509_ASN_ENCODING, ocsp_cert_revoked_issuer,
+ sizeof(ocsp_cert_revoked_issuer));
+ memset(&status, 0x55, sizeof(status));
+ status.cbSize = sizeof(status);
+ SetLastError(0xdeadbeef);
+ ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, 1, (void **)&certs[0],
+ 0, &revPara, &status);
+ ok(!ret, "success\n");
+ ok(GetLastError() == CRYPT_E_REVOKED, "got %08lx\n", GetLastError());
+ ok(status.dwError == CRYPT_E_REVOKED, "got %08lx\n", status.dwError);
+ ok(!status.dwIndex, "got %ld\n", status.dwIndex);
+ ok(!status.dwReason, "got %lu\n", status.dwReason);
+ CertFreeCertificateContext(revPara.pIssuerCert);
+ CertFreeCertificateContext(certs[0]);
}
static BYTE privKey[] = {
@@ -3753,45 +4305,42 @@ static void testAcquireCertPrivateKey(void)
CERT_KEY_CONTEXT keyContext;
/* Don't cache provider */
+ SetLastError(0xdeadbeef);
ret = CryptAcquireCertificatePrivateKey(cert, 0, NULL, &certCSP,
&keySpec, &callerFree);
- ok(ret, "CryptAcquireCertificatePrivateKey failed: %08lx\n",
- GetLastError());
- if (ret)
- {
- ok(callerFree, "Expected callerFree to be TRUE\n");
- CryptReleaseContext(certCSP, 0);
- }
+ ok(ret, "CryptAcquireCertificatePrivateKey failed: %08lx\n", GetLastError());
+ ok(GetLastError() == ERROR_SUCCESS, "got %08lx\n", GetLastError());
+ ok(callerFree, "Expected callerFree to be TRUE\n");
+ CryptReleaseContext(certCSP, 0);
+ SetLastError(0xdeadbeef);
ret = CryptAcquireCertificatePrivateKey(cert, 0, NULL, &certCSP,
NULL, NULL);
- ok(ret, "CryptAcquireCertificatePrivateKey failed: %08lx\n",
- GetLastError());
+ ok(ret, "CryptAcquireCertificatePrivateKey failed: %08lx\n", GetLastError());
+ ok(GetLastError() == ERROR_SUCCESS, "got %08lx\n", GetLastError());
CryptReleaseContext(certCSP, 0);
/* Use the key prov info's caching (there shouldn't be any) */
+ SetLastError(0xdeadbeef);
ret = CryptAcquireCertificatePrivateKey(cert,
CRYPT_ACQUIRE_USE_PROV_INFO_FLAG, NULL, &certCSP, &keySpec,
&callerFree);
- ok(ret, "CryptAcquireCertificatePrivateKey failed: %08lx\n",
- GetLastError());
- if (ret)
- {
- ok(callerFree, "Expected callerFree to be TRUE\n");
- CryptReleaseContext(certCSP, 0);
- }
+ ok(ret, "CryptAcquireCertificatePrivateKey failed: %08lx\n", GetLastError());
+ ok(GetLastError() == ERROR_SUCCESS, "got %08lx\n", GetLastError());
+ ok(callerFree, "Expected callerFree to be TRUE\n");
+ CryptReleaseContext(certCSP, 0);
/* Cache it (and check that it's cached) */
+ SetLastError(0xdeadbeef);
ret = CryptAcquireCertificatePrivateKey(cert,
CRYPT_ACQUIRE_CACHE_FLAG, NULL, &certCSP, &keySpec, &callerFree);
- ok(ret, "CryptAcquireCertificatePrivateKey failed: %08lx\n",
- GetLastError());
+ ok(ret, "CryptAcquireCertificatePrivateKey failed: %08lx\n", GetLastError());
+ ok(GetLastError() == ERROR_SUCCESS, "got %08lx\n", GetLastError());
ok(!callerFree, "Expected callerFree to be FALSE\n");
size = sizeof(keyContext);
ret = CertGetCertificateContextProperty(cert, CERT_KEY_CONTEXT_PROP_ID,
&keyContext, &size);
- ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
- GetLastError());
+ ok(ret, "CertGetCertificateContextProperty failed: %08lx\n", GetLastError());
/* Remove the cached provider */
CryptReleaseContext(keyContext.hCryptProv, 0);
@@ -3802,17 +4351,17 @@ static void testAcquireCertPrivateKey(void)
CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0,
&keyProvInfo);
/* Now use the key prov info's caching */
+ SetLastError(0xdeadbeef);
ret = CryptAcquireCertificatePrivateKey(cert,
CRYPT_ACQUIRE_USE_PROV_INFO_FLAG, NULL, &certCSP, &keySpec,
&callerFree);
- ok(ret, "CryptAcquireCertificatePrivateKey failed: %08lx\n",
- GetLastError());
+ ok(ret, "CryptAcquireCertificatePrivateKey failed: %08lx\n", GetLastError());
+ ok(GetLastError() == ERROR_SUCCESS, "got %08lx\n", GetLastError());
ok(!callerFree, "Expected callerFree to be FALSE\n");
size = sizeof(keyContext);
ret = CertGetCertificateContextProperty(cert, CERT_KEY_CONTEXT_PROP_ID,
&keyContext, &size);
- ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
- GetLastError());
+ ok(ret, "CertGetCertificateContextProperty failed: %08lx\n", GetLastError());
CryptReleaseContext(certCSP, 0);
CryptDestroyKey(key);
@@ -3828,7 +4377,7 @@ static void testAcquireCertPrivateKey(void)
ok(ret, "CryptExportKey failed: %08lx\n", GetLastError());
if (ret)
{
- LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size), encodedKey;
+ LPBYTE buf = malloc(size), encodedKey;
ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, buf, &size);
ok(ret, "CryptExportKey failed: %08lx\n", GetLastError());
@@ -3846,7 +4395,7 @@ static void testAcquireCertPrivateKey(void)
"Unexpected value\n");
LocalFree(encodedKey);
}
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
CryptDestroyKey(key);
}
@@ -3855,7 +4404,7 @@ static void testAcquireCertPrivateKey(void)
ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError());
if (ret)
{
- PCERT_PUBLIC_KEY_INFO info = HeapAlloc(GetProcessHeap(), 0, size);
+ PCERT_PUBLIC_KEY_INFO info = malloc(size);
ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
NULL, 0, NULL, info, &size);
@@ -3867,7 +4416,7 @@ static void testAcquireCertPrivateKey(void)
ok(!memcmp(info->PublicKey.pbData, asnEncodedPublicKey,
info->PublicKey.cbData), "Unexpected value\n");
}
- HeapFree(GetProcessHeap(), 0, info);
+ free(info);
}
CryptReleaseContext(csp, 0);
@@ -3992,7 +4541,7 @@ static void testKeyProvInfo(void)
ret = CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &size);
ok(ret, "CertGetCertificateContextProperty error %#lx\n", GetLastError());
- info = HeapAlloc(GetProcessHeap(), 0, size);
+ info = malloc(size);
ret = CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, info, &size);
ok(ret, "CertGetCertificateContextProperty error %#lx\n", GetLastError());
ok(!lstrcmpW(info->pwszContainerName, containerW), "got %s\n", wine_dbgstr_w(info->pwszContainerName));
@@ -4010,7 +4559,7 @@ static void testKeyProvInfo(void)
ok(info->rgProvParam[1].cbData == param[1].cbData, "got %#lx\n", info->rgProvParam[1].cbData);
ok(!memcmp(info->rgProvParam[1].pbData, param[1].pbData, param[1].cbData), "param2 mismatch\n");
ok(info->rgProvParam[1].dwFlags == param[1].dwFlags, "got %#lx\n", info->rgProvParam[1].dwFlags);
- HeapFree(GetProcessHeap(), 0, info);
+ free(info);
ret = CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_NEW, NULL);
ok(ret, "CertAddCertificateContextToStore error %#lx\n", GetLastError());
@@ -4029,7 +4578,7 @@ static void testKeyProvInfo(void)
ret = CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &size);
ok(ret, "CertGetCertificateContextProperty error %#lx\n", GetLastError());
- info = HeapAlloc(GetProcessHeap(), 0, size);
+ info = malloc(size);
ret = CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, info, &size);
ok(ret, "CertGetCertificateContextProperty error %#lx\n", GetLastError());
ok(!lstrcmpW(info->pwszContainerName, containerW), "got %s\n", wine_dbgstr_w(info->pwszContainerName));
@@ -4047,7 +4596,7 @@ static void testKeyProvInfo(void)
ok(info->rgProvParam[1].cbData == param[1].cbData, "got %#lx\n", info->rgProvParam[1].cbData);
ok(!memcmp(info->rgProvParam[1].pbData, param[1].pbData, param[1].cbData), "param2 mismatch\n");
ok(info->rgProvParam[1].dwFlags == param[1].dwFlags, "got %#lx\n", info->rgProvParam[1].dwFlags);
- HeapFree(GetProcessHeap(), 0, info);
+ free(info);
ret = CertDeleteCertificateFromStore(cert);
ok(ret, "CertDeleteCertificateFromStore error %#lx\n", GetLastError());
@@ -4126,7 +4675,7 @@ static void test_VerifySignature(void)
ok(!status, "got %#lx\n", status);
ok(hash_len == sizeof(hash_value), "got %lu\n", hash_len);
- sig_value = HeapAlloc(GetProcessHeap(), 0, info->Signature.cbData);
+ sig_value = malloc(info->Signature.cbData);
for (i = 0; i < info->Signature.cbData; i++)
sig_value[i] = info->Signature.pbData[info->Signature.cbData - i - 1];
@@ -4134,7 +4683,7 @@ static void test_VerifySignature(void)
status = BCryptVerifySignature(bkey, &pad, hash_value, sizeof(hash_value), sig_value, info->Signature.cbData, BCRYPT_PAD_PKCS1);
ok(!status, "got %#lx\n", status);
- HeapFree(GetProcessHeap(), 0, sig_value);
+ free(sig_value);
BCryptDestroyHash(bhash);
BCryptCloseAlgorithmProvider(alg, 0);
BCryptDestroyKey(bkey);
diff --git a/dlls/crypt32/tests/chain.c b/dlls/crypt32/tests/chain.c
index 9ed1b28bf70..32f00801799 100644
--- wine/dlls/crypt32/tests/chain.c
+++ wine/dlls/crypt32/tests/chain.c
@@ -4958,6 +4958,13 @@ static const ChainPolicyCheck msRootPolicyCheck[] = {
{ 0, CERT_E_UNTRUSTEDROOT, 0, 0, NULL }, NULL, 0 },
};
+static const ChainPolicyCheck msRootPolicyCheck_approot[] = {
+ { { ARRAY_SIZE(chain32), chain32 },
+ { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, TODO_ELEMENTS },
+ { { ARRAY_SIZE(chain33), chain33 },
+ { 0, 0, 0, 0, NULL }, NULL, 0 },
+};
+
static const char *num_to_str(WORD num)
{
static char buf[6];
@@ -5295,8 +5302,16 @@ static void check_ssl_policy(void)
static void check_msroot_policy(void)
{
+ CERT_CHAIN_POLICY_PARA para;
+
CHECK_CHAIN_POLICY_STATUS_ARRAY(CERT_CHAIN_POLICY_MICROSOFT_ROOT, NULL,
msRootPolicyCheck, &may2020, NULL);
+
+ para.cbSize = sizeof(para);
+ para.pvExtraPolicyPara = NULL;
+ para.dwFlags = MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG;
+ CHECK_CHAIN_POLICY_STATUS_ARRAY(CERT_CHAIN_POLICY_MICROSOFT_ROOT, NULL,
+ msRootPolicyCheck_approot, &may2020, &para);
}
static void testVerifyCertChainPolicy(void)
diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c
index 9dabe58efba..527e663860a 100644
--- wine/dlls/crypt32/tests/encode.c
+++ wine/dlls/crypt32/tests/encode.c
@@ -2315,10 +2315,10 @@ static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 };
static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 };
-static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 };
-static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
-static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 };
-static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
+static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x02,0x00,0x01 };
+static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x02,0x00,0x01 };
+static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x02,0x00,0x01 };
+static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x02,0x00,0x01 };
struct EncodedRSAPubKey
{
@@ -2351,7 +2351,7 @@ static void test_encodeRsaPublicKey(DWORD dwEncoding)
hdr->aiKeyAlg = CALG_RSA_KEYX;
rsaPubKey->magic = 0x31415352;
rsaPubKey->bitlen = sizeof(modulus1) * 8;
- rsaPubKey->pubexp = 65537;
+ rsaPubKey->pubexp = 131073;
memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
sizeof(modulus1));
@@ -2480,7 +2480,7 @@ static void test_decodeRsaPublicKey(DWORD dwEncoding)
"Expected magic RSA1, got %08lx\n", rsaPubKey->magic);
ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
"Wrong bit len %ld\n", rsaPubKey->bitlen);
- ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %ld\n",
+ ok(rsaPubKey->pubexp == 131073, "Expected pubexp 131073, got %ld\n",
rsaPubKey->pubexp);
ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
@@ -2497,7 +2497,7 @@ static void test_encodeRsaPublicKey_Bcrypt(DWORD dwEncoding)
BOOL ret;
BYTE *buf = NULL;
DWORD bufSize = 0, i;
- BYTE pubexp[] = {0x01,0x00,0x01,0x00}; /* 65537 */
+ BYTE pubexp[] = {0x01,0x00,0x02,0x00}; /* 131073 */
/* Verify that the Magic value doesn't matter */
hdr->Magic = 1;
@@ -2568,7 +2568,7 @@ static void test_decodeRsaPublicKey_Bcrypt(DWORD dwEncoding)
if (ret)
{
BCRYPT_RSAKEY_BLOB *hdr = (BCRYPT_RSAKEY_BLOB *)buf;
- BYTE pubexp[] = {0xff,0xff,0xff,0xff}, pubexp_expected[] = {0x01,0x00,0x01};
+ BYTE pubexp[] = {0xff,0xff,0xff,0xcc}, pubexp_expected[] = {0x01,0x00,0x02};
/* CNG_RSA_PUBLIC_KEY_BLOB stores the exponent
* in big-endian format, so we need to convert it to little-endian
*/
@@ -2584,15 +2584,15 @@ static void test_decodeRsaPublicKey_Bcrypt(DWORD dwEncoding)
/* Windows decodes the exponent to 3 bytes, since it will fit.
* Our implementation currently unconditionally decodes to a DWORD (4 bytes)
*/
- todo_wine ok(hdr->cbPublicExp == 3, "Expected cbPublicExp 3, got %ld\n", hdr->cbPublicExp);
+ ok(hdr->cbPublicExp == 3, "Expected cbPublicExp 3, got %ld\n", hdr->cbPublicExp);
ok(hdr->cbModulus == rsaPubKeys[i].decodedModulusLen,
"Wrong modulus len %ld\n", hdr->cbModulus);
ok(hdr->cbPrime1 == 0,"Wrong cbPrime1 %ld\n", hdr->cbPrime1);
ok(hdr->cbPrime2 == 0,"Wrong cbPrime2 %ld\n", hdr->cbPrime2);
ok(!memcmp(pubexp, pubexp_expected, sizeof(pubexp_expected)), "Wrong exponent\n");
- todo_wine ok(pubexp[3] == 0xff, "Got %02x\n", pubexp[3]);
+ ok(pubexp[3] == 0xcc, "Got %02x\n", pubexp[3]);
- leModulus = HeapAlloc(GetProcessHeap(), 0, hdr->cbModulus);
+ leModulus = malloc(hdr->cbModulus);
/*
* CNG_RSA_PUBLIC_KEY_BLOB stores the modulus in big-endian format,
* so we need to convert it to little-endian
@@ -2603,7 +2603,7 @@ static void test_decodeRsaPublicKey_Bcrypt(DWORD dwEncoding)
rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
"Unexpected modulus\n");
LocalFree(buf);
- LocalFree(leModulus);
+ free(leModulus);
}
}
}
@@ -2799,13 +2799,13 @@ static void test_decodeExtensions(DWORD dwEncoding)
ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
exts[i].encoded, exts[i].encoded[1] + 2, 0, NULL, NULL, &bufSize);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
- buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufSize);
+ buf = calloc(1, bufSize);
if (buf)
{
ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
exts[i].encoded, exts[i].encoded[1] + 2, 0, NULL, buf, &bufSize);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
}
}
@@ -3770,14 +3770,14 @@ static void test_decodeCRLDistPoints(DWORD dwEncoding)
distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2, 0,
NULL, NULL, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
- buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+ buf = calloc(1, size);
if (buf)
{
ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2, 0,
NULL, buf, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
}
@@ -4906,13 +4906,13 @@ static void test_decodeEnhancedKeyUsage(DWORD dwEncoding)
ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
encodedUsage, sizeof(encodedUsage), 0, NULL, NULL, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
- buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+ buf = calloc(1, size);
if (buf)
{
ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
encodedUsage, sizeof(encodedUsage), 0, NULL, buf, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
}
@@ -5391,14 +5391,14 @@ static void test_decodeAuthorityInfoAccess(DWORD dwEncoding)
authorityInfoAccessWithUrlAndIPAddr,
sizeof(authorityInfoAccessWithUrlAndIPAddr), 0, NULL, NULL, &size);
ok(ret, "CryptDecodeObjectEx failed: %lx\n", GetLastError());
- buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+ buf = calloc(1, size);
if (buf)
{
ret = CryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_INFO_ACCESS,
authorityInfoAccessWithUrlAndIPAddr,
sizeof(authorityInfoAccessWithUrlAndIPAddr), 0, NULL, buf, &size);
ok(ret, "CryptDecodeObjectEx failed: %lx\n", GetLastError());
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
}
@@ -6354,13 +6354,13 @@ static void test_decodePKCSAttributes(DWORD dwEncoding)
ret = CryptDecodeObjectEx(dwEncoding, PKCS_ATTRIBUTES,
doublePKCSAttributes, sizeof(doublePKCSAttributes), 0, NULL, NULL, &size);
ok(ret, "CryptDecodeObjectEx failed: %lx\n", GetLastError());
- buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+ buf = calloc(1, size);
if (buf)
{
ret = CryptDecodeObjectEx(dwEncoding, PKCS_ATTRIBUTES,
doublePKCSAttributes, sizeof(doublePKCSAttributes), 0, NULL, buf, &size);
ok(ret, "CryptDecodeObjectEx failed: %lx\n", GetLastError());
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
}
@@ -6522,14 +6522,14 @@ static void test_decodePKCSSMimeCapabilities(DWORD dwEncoding)
ret = CryptDecodeObjectEx(dwEncoding, PKCS_SMIME_CAPABILITIES,
twoCapabilities, sizeof(twoCapabilities), 0, NULL, NULL, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
- ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+ ptr = calloc(1, size);
if (ptr)
{
SetLastError(0xdeadbeef);
ret = CryptDecodeObjectEx(dwEncoding, PKCS_SMIME_CAPABILITIES,
twoCapabilities, sizeof(twoCapabilities), 0, NULL, ptr, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
- HeapFree(GetProcessHeap(), 0, ptr);
+ free(ptr);
}
}
@@ -7645,13 +7645,13 @@ static void test_decodeCertPolicies(DWORD dwEncoding)
ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_POLICIES,
twoPolicies, sizeof(twoPolicies), 0, NULL, NULL, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
- info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+ info = calloc(1, size);
if (info)
{
ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_POLICIES,
twoPolicies, sizeof(twoPolicies), 0, NULL, info, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
- HeapFree(GetProcessHeap(), 0, info);
+ free(info);
}
}
@@ -7788,14 +7788,14 @@ static void test_decodeCertPolicyMappings(DWORD dwEncoding)
policyMappingWithTwoMappings, sizeof(policyMappingWithTwoMappings), 0,
NULL, NULL, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
- info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+ info = calloc(1, size);
if (info)
{
ret = CryptDecodeObjectEx(dwEncoding, mappingOids[i],
policyMappingWithTwoMappings, sizeof(policyMappingWithTwoMappings), 0,
NULL, info, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
- HeapFree(GetProcessHeap(), 0, info);
+ free(info);
}
}
}
@@ -8225,7 +8225,6 @@ static void test_decodeRsaPrivateKey(DWORD dwEncoding)
}
}
-/* Free *pInfo with HeapFree */
static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
{
BOOL ret;
@@ -8262,7 +8261,7 @@ static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
NULL, 0, NULL, NULL, &size);
ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError());
- *pInfo = HeapAlloc(GetProcessHeap(), 0, size);
+ *pInfo = malloc(size);
if (*pInfo)
{
ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
@@ -8411,7 +8410,7 @@ static void testPortPublicKeyInfo(void)
testExportPublicKey(csp, &info);
testImportPublicKey(csp, info);
- HeapFree(GetProcessHeap(), 0, info);
+ free(info);
CryptReleaseContext(csp, 0);
ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV_A, PROV_RSA_FULL,
CRYPT_DELETEKEYSET);
@@ -8674,6 +8673,26 @@ static const BYTE ocsp_basic_response[] = {
0x33, 0x36, 0x30, 0x31, 0x5a
};
+static const BYTE ocsp_basic_response2[] = {
+ 0x30, 0x81, 0xbe, 0xa1, 0x34, 0x30, 0x32, 0x31, 0x0b, 0x30, 0x09, 0x06,
+ 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14,
+ 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x4c, 0x65, 0x74, 0x27, 0x73,
+ 0x20, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x31, 0x0b, 0x30, 0x09,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x02, 0x52, 0x33, 0x18, 0x0f, 0x32,
+ 0x30, 0x32, 0x32, 0x31, 0x30, 0x32, 0x30, 0x30, 0x36, 0x30, 0x31, 0x30,
+ 0x30, 0x5a, 0x30, 0x75, 0x30, 0x73, 0x30, 0x4b, 0x30, 0x09, 0x06, 0x05,
+ 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x48, 0xda, 0xc9,
+ 0xa0, 0xfb, 0x2b, 0xd3, 0x2d, 0x4f, 0xf0, 0xde, 0x68, 0xd2, 0xf5, 0x67,
+ 0xb7, 0x35, 0xf9, 0xb3, 0xc4, 0x04, 0x14, 0x14, 0x2e, 0xb3, 0x17, 0xb7,
+ 0x58, 0x56, 0xcb, 0xae, 0x50, 0x09, 0x40, 0xe6, 0x1f, 0xaf, 0x9d, 0x8b,
+ 0x14, 0xc2, 0xc6, 0x02, 0x12, 0x03, 0x26, 0x1c, 0x82, 0x80, 0xf3, 0x8c,
+ 0x13, 0xef, 0xae, 0x83, 0x9d, 0x89, 0xb9, 0xcd, 0x59, 0x83, 0x5b, 0x80,
+ 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x32, 0x31, 0x30, 0x32, 0x30, 0x30,
+ 0x36, 0x30, 0x30, 0x30, 0x30, 0x5a, 0xa0, 0x11, 0x18, 0x0f, 0x32, 0x30,
+ 0x32, 0x32, 0x31, 0x30, 0x32, 0x37, 0x30, 0x35, 0x35, 0x39, 0x35, 0x38,
+ 0x5a
+};
+
static const BYTE ocsp_basic_response_revoked[] = {
0x30, 0x81, 0xb1, 0xa2, 0x16, 0x04, 0x14, 0xa4, 0x8d, 0xe5, 0xbe, 0x7c,
0x79, 0xe4, 0x70, 0x23, 0x6d, 0x2e, 0x29, 0x34, 0xad, 0x23, 0x58, 0xdc,
@@ -8759,22 +8778,36 @@ static void test_decodeOCSPBasicResponseInfo(DWORD dwEncoding)
static const BYTE resp_id2[] = {
0xa4, 0x8d, 0xe5, 0xbe, 0x7c, 0x79, 0xe4, 0x70, 0x23, 0x6d, 0x2e, 0x29, 0x34, 0xad, 0x23, 0x58,
0xdc, 0xf5, 0x31, 0x7f};
+ static const BYTE resp_id3[] = {
+ 0x30, 0x32, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+ 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x4c, 0x65, 0x74, 0x27, 0x73, 0x20,
+ 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x02, 0x52, 0x33};
static const BYTE name_hash[] = {
0xe4, 0xe3, 0x95, 0xa2, 0x29, 0xd3, 0xd4, 0xc1, 0xc3, 0x1f, 0xf0, 0x98, 0x0c, 0x0b, 0x4e, 0xc0,
0x09, 0x8a, 0xab, 0xd8};
static const BYTE name_hash2[] = {
0x74, 0xb4, 0xe7, 0x23, 0x19, 0xc7, 0x65, 0x92, 0x15, 0x40, 0x44, 0x7b, 0xc7, 0xce, 0x3e, 0x90,
0xc2, 0x18, 0x76, 0xeb};
+ static const BYTE name_hash3[] = {
+ 0x48, 0xda, 0xc9, 0xa0, 0xfb, 0x2b, 0xd3, 0x2d, 0x4f, 0xf0, 0xde, 0x68, 0xd2, 0xf5, 0x67, 0xb7,
+ 0x35, 0xf9, 0xb3, 0xc4};
static const BYTE key_hash[] = {
0xb7, 0x6b, 0xa2, 0xea, 0xa8, 0xaa, 0x84, 0x8c, 0x79, 0xea, 0xb4, 0xda, 0x0f, 0x98, 0xb2, 0xc5,
0x95, 0x76, 0xb9, 0xf4};
static const BYTE key_hash2[] = {
0xa4, 0x8d, 0xe5, 0xbe, 0x7c, 0x79, 0xe4, 0x70, 0x23, 0x6d, 0x2e, 0x29, 0x34, 0xad, 0x23, 0x58,
0xdc, 0xf5, 0x31, 0x7f};
+ static const BYTE key_hash3[] = {
+ 0x14, 0x2e, 0xb3, 0x17, 0xb7, 0x58, 0x56, 0xcb, 0xae, 0x50, 0x09, 0x40, 0xe6, 0x1f, 0xaf, 0x9d,
+ 0x8b, 0x14, 0xc2, 0xc6};
static const BYTE serial[] = {
0xb1, 0xc1, 0x87, 0x54, 0x54, 0xac, 0x1e, 0x55, 0x40, 0xfb, 0xef, 0xd9, 0x6d, 0x8f, 0x49, 0x08};
static const BYTE serial2[] = {
0x2f, 0x57, 0xa4, 0x85, 0xa2, 0xe3, 0x52, 0x54, 0x9a, 0x3b, 0x85, 0x98, 0xa2, 0x67, 0x2e, 0x0d};
+ static const BYTE serial3[] = {
+ 0x5b, 0x83, 0x59, 0xcd, 0xb9, 0x89, 0x9d, 0x83, 0xae, 0xef, 0x13, 0x8c, 0xf3, 0x80, 0x82, 0x1c,
+ 0x26, 0x03};
OCSP_BASIC_RESPONSE_INFO *info;
OCSP_BASIC_RESPONSE_ENTRY *entry;
OCSP_BASIC_REVOKED_INFO *revoked;
@@ -8801,11 +8834,11 @@ static void test_decodeOCSPBasicResponseInfo(DWORD dwEncoding)
ok(entry->CertId.HashAlgorithm.Parameters.cbData == 2, "got %lu\n", entry->CertId.HashAlgorithm.Parameters.cbData);
ok(entry->CertId.HashAlgorithm.Parameters.pbData[0] == 5, "got 0x%02x\n", entry->CertId.HashAlgorithm.Parameters.pbData[0]);
ok(!entry->CertId.HashAlgorithm.Parameters.pbData[1], "got 0x%02x\n", entry->CertId.HashAlgorithm.Parameters.pbData[1]);
- ok(entry->CertId.IssuerNameHash.cbData == 20, "got %lu\n", entry->CertId.IssuerNameHash.cbData);
+ ok(entry->CertId.IssuerNameHash.cbData == sizeof(name_hash), "got %lu\n", entry->CertId.IssuerNameHash.cbData);
ok(!memcmp(entry->CertId.IssuerNameHash.pbData, name_hash, sizeof(name_hash)), "wrong data\n");
- ok(entry->CertId.IssuerKeyHash.cbData == 20, "got %lu\n", entry->CertId.IssuerKeyHash.cbData);
+ ok(entry->CertId.IssuerKeyHash.cbData == sizeof(key_hash), "got %lu\n", entry->CertId.IssuerKeyHash.cbData);
ok(!memcmp(entry->CertId.IssuerKeyHash.pbData, key_hash, sizeof(key_hash)), "wrong data\n");
- ok(entry->CertId.SerialNumber.cbData == 16, "got %lu\n", entry->CertId.SerialNumber.cbData);
+ ok(entry->CertId.SerialNumber.cbData == sizeof(serial), "got %lu\n", entry->CertId.SerialNumber.cbData);
ok(!memcmp(entry->CertId.SerialNumber.pbData, serial, sizeof(serial)), "wrong data\n");
ok(entry->dwCertStatus == 0, "got %lu\n", entry->dwCertStatus);
ok(entry->pRevokedInfo == NULL, "got %p\n", entry->pRevokedInfo);
@@ -8824,9 +8857,8 @@ static void test_decodeOCSPBasicResponseInfo(DWORD dwEncoding)
size = 0;
ret = CryptDecodeObjectEx(dwEncoding, OCSP_BASIC_RESPONSE, ocsp_basic_response_revoked,
sizeof(ocsp_basic_response_revoked), CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
- todo_wine ok(ret, "got %08lx\n", GetLastError());
+ ok(ret, "got %08lx\n", GetLastError());
- if (ret) {
ok(!info->dwVersion, "got %lu\n", info->dwVersion);
ok(info->dwResponderIdChoice == 2, "got %lu\n", info->dwResponderIdChoice);
ok(info->ByKeyResponderId.cbData == sizeof(resp_id), "got %lu\n", info->ByKeyResponderId.cbData);
@@ -8841,11 +8873,11 @@ static void test_decodeOCSPBasicResponseInfo(DWORD dwEncoding)
ok(entry->CertId.HashAlgorithm.Parameters.cbData == 2, "got %lu\n", entry->CertId.HashAlgorithm.Parameters.cbData);
ok(entry->CertId.HashAlgorithm.Parameters.pbData[0] == 5, "got 0x%02x\n", entry->CertId.HashAlgorithm.Parameters.pbData[0]);
ok(!entry->CertId.HashAlgorithm.Parameters.pbData[1], "got 0x%02x\n", entry->CertId.HashAlgorithm.Parameters.pbData[1]);
- ok(entry->CertId.IssuerNameHash.cbData == 20, "got %lu\n", entry->CertId.IssuerNameHash.cbData);
+ ok(entry->CertId.IssuerNameHash.cbData == sizeof(name_hash2), "got %lu\n", entry->CertId.IssuerNameHash.cbData);
ok(!memcmp(entry->CertId.IssuerNameHash.pbData, name_hash2, sizeof(name_hash2)), "wrong data\n");
- ok(entry->CertId.IssuerKeyHash.cbData == 20, "got %lu\n", entry->CertId.IssuerKeyHash.cbData);
+ ok(entry->CertId.IssuerKeyHash.cbData == sizeof(key_hash2), "got %lu\n", entry->CertId.IssuerKeyHash.cbData);
ok(!memcmp(entry->CertId.IssuerKeyHash.pbData, key_hash2, sizeof(key_hash2)), "wrong data\n");
- ok(entry->CertId.SerialNumber.cbData == 16, "got %lu\n", entry->CertId.SerialNumber.cbData);
+ ok(entry->CertId.SerialNumber.cbData == sizeof(serial2), "got %lu\n", entry->CertId.SerialNumber.cbData);
ok(!memcmp(entry->CertId.SerialNumber.pbData, serial2, sizeof(serial2)), "wrong data\n");
ok(entry->dwCertStatus == 1, "got %lu\n", entry->dwCertStatus);
ok(entry->pRevokedInfo != NULL, "got NULL\n");
@@ -8864,7 +8896,46 @@ static void test_decodeOCSPBasicResponseInfo(DWORD dwEncoding)
ok(!info->cExtension, "got %lu\n", info->cExtension);
ok(info->rgExtension == NULL, "got %p\n", info->rgExtension);
- }
+ LocalFree(info);
+
+ size = 0;
+ ret = CryptDecodeObjectEx(dwEncoding, OCSP_BASIC_RESPONSE, ocsp_basic_response2,
+ sizeof(ocsp_basic_response2), CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
+ ok(ret, "got %08lx\n", GetLastError());
+
+ ok(!info->dwVersion, "got %lu\n", info->dwVersion);
+ ok(info->dwResponderIdChoice == 1, "got %lu\n", info->dwResponderIdChoice);
+ ok(info->ByNameResponderId.cbData == sizeof(resp_id3), "got %lu\n", info->ByNameResponderId.cbData);
+ ok(!memcmp(info->ByNameResponderId.pbData, resp_id3, sizeof(resp_id3)), "wrong data\n");
+
+ ok(info->ProducedAt.dwLowDateTime == 1408824832, "got %lu\n", info->ProducedAt.dwLowDateTime);
+ ok(info->ProducedAt.dwHighDateTime == 30991433, "got %lu\n", info->ProducedAt.dwHighDateTime);
+ ok(info->cResponseEntry == 1, "got %lu\n", info->cResponseEntry);
+ ok(info->rgResponseEntry != NULL, "got %p\n", info->rgResponseEntry);
+
+ entry = info->rgResponseEntry;
+ ok(!strcmp(entry->CertId.HashAlgorithm.pszObjId, szOID_OIWSEC_sha1), "got '%s'\n", entry->CertId.HashAlgorithm.pszObjId);
+ ok(entry->CertId.HashAlgorithm.Parameters.cbData == 2, "got %lu\n", entry->CertId.HashAlgorithm.Parameters.cbData);
+ ok(entry->CertId.HashAlgorithm.Parameters.pbData[0] == 5, "got 0x%02x\n", entry->CertId.HashAlgorithm.Parameters.pbData[0]);
+ ok(!entry->CertId.HashAlgorithm.Parameters.pbData[1], "got 0x%02x\n", entry->CertId.HashAlgorithm.Parameters.pbData[1]);
+ ok(entry->CertId.IssuerNameHash.cbData == sizeof(name_hash3), "got %lu\n", entry->CertId.IssuerNameHash.cbData);
+ ok(!memcmp(entry->CertId.IssuerNameHash.pbData, name_hash3, sizeof(name_hash3)), "wrong data\n");
+
+ ok(entry->CertId.IssuerKeyHash.cbData == sizeof(key_hash3), "got %lu\n", entry->CertId.IssuerKeyHash.cbData);
+ ok(!memcmp(entry->CertId.IssuerKeyHash.pbData, key_hash3, sizeof(key_hash3)), "wrong data\n");
+ ok(entry->CertId.SerialNumber.cbData == sizeof(serial3), "got %lu\n", entry->CertId.SerialNumber.cbData);
+ ok(!memcmp(entry->CertId.SerialNumber.pbData, serial3, sizeof(serial3)), "wrong data\n");
+ ok(entry->dwCertStatus == 0, "got %lu\n", entry->dwCertStatus);
+ ok(entry->pRevokedInfo == NULL, "got %p\n", entry->pRevokedInfo);
+ ok(entry->ThisUpdate.dwLowDateTime == 808824832, "got %lu\n", entry->ThisUpdate.dwLowDateTime);
+ ok(entry->ThisUpdate.dwHighDateTime == 30991433, "got %lu\n", entry->ThisUpdate.dwHighDateTime);
+ ok(entry->NextUpdate.dwLowDateTime == 1474872064, "got %lu\n", entry->NextUpdate.dwLowDateTime);
+ ok(entry->NextUpdate.dwHighDateTime == 30992841, "got %lu\n", entry->NextUpdate.dwHighDateTime);
+ ok(!entry->cExtension, "got %lu\n", entry->cExtension);
+ ok(entry->rgExtension == NULL, "got %p\n", entry->rgExtension);
+
+ ok(!info->cExtension, "got %lu\n", info->cExtension);
+ ok(info->rgExtension == NULL, "got %p\n", info->rgExtension);
LocalFree(info);
}
diff --git a/dlls/crypt32/tests/main.c b/dlls/crypt32/tests/main.c
index 19dde3fb28f..1b125e89d50 100644
--- wine/dlls/crypt32/tests/main.c
+++ wine/dlls/crypt32/tests/main.c
@@ -349,7 +349,7 @@ static void test_getDefaultCryptProv(void)
prov = pI_CryptGetDefaultCryptProv(test_prov[i].algid);
if (!prov)
{
- todo_wine_if(test_prov[i].algid == CALG_DSS_SIGN || test_prov[i].algid == CALG_NO_SIGN)
+todo_wine_if(test_prov[i].algid == CALG_DSS_SIGN || test_prov[i].algid == CALG_NO_SIGN)
ok(test_prov[i].optional, "%lu: I_CryptGetDefaultCryptProv(%#x) failed\n", i, test_prov[i].algid);
continue;
}
diff --git a/dlls/crypt32/tests/message.c b/dlls/crypt32/tests/message.c
index fa4790a2a6b..e6339553e52 100644
--- wine/dlls/crypt32/tests/message.c
+++ wine/dlls/crypt32/tests/message.c
@@ -688,14 +688,14 @@ static void test_hash_message(void)
/* Actually attempting to get the hashed data fails, perhaps because
* detached is FALSE.
*/
- hashedBlob = HeapAlloc(GetProcessHeap(), 0, hashedBlobSize);
+ hashedBlob = malloc(hashedBlobSize);
SetLastError(0xdeadbeef);
ret = CryptHashMessage(&para, FALSE, 2, toHash, hashSize, hashedBlob,
&hashedBlobSize, NULL, NULL);
ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
"expected CRYPT_E_MSG_ERROR, got 0x%08lx (%ld)\n", GetLastError(),
GetLastError());
- HeapFree(GetProcessHeap(), 0, hashedBlob);
+ free(hashedBlob);
}
/* Repeating tests with fDetached = TRUE results in success */
SetLastError(0xdeadbeef);
@@ -704,7 +704,7 @@ static void test_hash_message(void)
ok(ret, "CryptHashMessage failed: 0x%08lx\n", GetLastError());
if (ret)
{
- hashedBlob = HeapAlloc(GetProcessHeap(), 0, hashedBlobSize);
+ hashedBlob = malloc(hashedBlobSize);
SetLastError(0xdeadbeef);
ret = CryptHashMessage(&para, TRUE, 2, toHash, hashSize, hashedBlob,
&hashedBlobSize, NULL, NULL);
@@ -713,7 +713,7 @@ static void test_hash_message(void)
"unexpected size of detached blob %ld\n", hashedBlobSize);
ok(!memcmp(hashedBlob, detachedHashBlob, hashedBlobSize),
"unexpected detached blob value\n");
- HeapFree(GetProcessHeap(), 0, hashedBlob);
+ free(hashedBlob);
}
/* Hashing a single item with fDetached = FALSE also succeeds */
SetLastError(0xdeadbeef);
@@ -722,7 +722,7 @@ static void test_hash_message(void)
ok(ret, "CryptHashMessage failed: 0x%08lx\n", GetLastError());
if (ret)
{
- hashedBlob = HeapAlloc(GetProcessHeap(), 0, hashedBlobSize);
+ hashedBlob = malloc(hashedBlobSize);
ret = CryptHashMessage(&para, FALSE, 1, toHash, hashSize, hashedBlob,
&hashedBlobSize, NULL, NULL);
ok(ret, "CryptHashMessage failed: 0x%08lx\n", GetLastError());
@@ -730,7 +730,7 @@ static void test_hash_message(void)
"unexpected size of detached blob %ld\n", hashedBlobSize);
ok(!memcmp(hashedBlob, hashBlob, hashedBlobSize),
"unexpected detached blob value\n");
- HeapFree(GetProcessHeap(), 0, hashedBlob);
+ free(hashedBlob);
}
/* Check the computed hash value too. You don't need to get the encoded
* blob to get it.
@@ -743,7 +743,7 @@ static void test_hash_message(void)
computedHashSize);
if (ret)
{
- computedHash = HeapAlloc(GetProcessHeap(), 0, computedHashSize);
+ computedHash = malloc(computedHashSize);
SetLastError(0xdeadbeef);
ret = CryptHashMessage(&para, TRUE, 2, toHash, hashSize, NULL,
&hashedBlobSize, computedHash, &computedHashSize);
@@ -752,7 +752,7 @@ static void test_hash_message(void)
"unexpected size of hash value %ld\n", computedHashSize);
ok(!memcmp(computedHash, hashVal, computedHashSize),
"unexpected value\n");
- HeapFree(GetProcessHeap(), 0, computedHash);
+ free(computedHash);
}
}
diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c
index f779d70695e..16f7402c613 100644
--- wine/dlls/crypt32/tests/msg.c
+++ wine/dlls/crypt32/tests/msg.c
@@ -274,14 +274,14 @@ static void check_param(LPCSTR test, HCRYPTMSG msg, DWORD param,
ret = CryptMsgGetParam(msg, param, 0, NULL, &size);
ok(ret, "%s: CryptMsgGetParam failed: %08lx\n", test, GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, size);
+ buf = malloc(size);
ret = CryptMsgGetParam(msg, param, 0, buf, &size);
ok(ret, "%s: CryptMsgGetParam failed: %08lx\n", test, GetLastError());
ok(size == expectedSize, "%s: expected size %ld, got %ld\n", test,
expectedSize, size);
if (size == expectedSize && size)
ok(!memcmp(buf, expected, size), "%s: unexpected data\n", test);
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
static void test_data_msg_open(void)
diff --git a/dlls/crypt32/tests/object.c b/dlls/crypt32/tests/object.c
index 22936d3738d..a3c7c8c0743 100644
--- wine/dlls/crypt32/tests/object.c
+++ wine/dlls/crypt32/tests/object.c
@@ -95,130 +95,10 @@ L"MIIBiQYJKoZIhvcNAQcCoIIBejCCAXYCAQExDjAMBggqhkiG9w0CBQUAMBMGCSqG"
"s+9Z0WbRm8CatppebW9tDVmpqm7pLKAe7sJgvFm+P2MGjckRHSNkku8u/FcppK/g"
"7pMZOVHkRLgLKPSoDQ==";
-/* Self-signed .exe, built with tcc, signed with signtool
- * (and a certificate generated on a self-signed CA).
- *
- * small.c:
- * int _start()
- * {
- * return 0;
- * }
- *
- * tcc -nostdlib small.c
- * signtool sign /v /f codesign.pfx small.exe
- */
-static const BYTE signed_pe_blob[] =
-{
- 0x4D,0x5A,0x90,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x0E,0x1F,0xBA,0x0E,0x00,0xB4,0x09,0xCD,
- 0x21,0xB8,0x01,0x4C,0xCD,0x21,0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,0x63,0x61,0x6E,0x6E,0x6F,
- 0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6E,0x20,0x69,0x6E,0x20,0x44,0x4F,0x53,0x20,0x6D,0x6F,0x64,0x65,0x2E,0x0D,0x0D,0x0A,
- 0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x45,0x00,0x00,0x4C,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0xE0,0x00,0x0F,0x03,0x0B,0x01,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x10,0x00,0x00,0x00,0x02,0x00,0x00,
- 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x02,0x00,0x00,
- 0xE7,0x0C,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x68,0x05,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2E,0x74,0x65,0x78,0x74,0x00,0x00,0x00,
- 0x18,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0x89,0xE5,0x81,0xEC,0x00,0x00,0x00,0x00,0x90,0xB8,0x00,0x00,0x00,0x00,0xE9,
- 0x00,0x00,0x00,0x00,0xC9,0xC3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x05,0x00,0x00,0x00,0x02,0x02,0x00,
- /* Start of the signature overlay */
- 0x30,0x82,0x05,0x5A,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x02,0xA0,0x82,0x05,0x4B,0x30,0x82,0x05,0x47,0x02,
- 0x01,0x01,0x31,0x0B,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x30,0x4C,0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,
- 0x82,0x37,0x02,0x01,0x04,0xA0,0x3E,0x30,0x3C,0x30,0x17,0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x0F,0x30,
- 0x09,0x03,0x01,0x00,0xA0,0x04,0xA2,0x02,0x80,0x00,0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,
- 0x14,0xA0,0x95,0xDE,0xBD,0x1A,0xB7,0x86,0xAF,0x50,0x63,0xD8,0x8F,0x90,0xD5,0x49,0x96,0x4E,0x44,0xF0,0x71,0xA0,0x82,0x03,
- 0x1D,0x30,0x82,0x03,0x19,0x30,0x82,0x02,0x01,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x96,0x53,0x2C,0xC9,0x23,0x56,0x8A,0x87,
- 0x42,0x30,0x3E,0xD5,0x8D,0x72,0xD5,0x25,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,
- 0x17,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x03,0x13,0x0C,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F,0x74,
- 0x30,0x1E,0x17,0x0D,0x31,0x36,0x30,0x33,0x30,0x33,0x32,0x30,0x32,0x37,0x30,0x37,0x5A,0x17,0x0D,0x34,0x39,0x31,0x32,0x33,
- 0x31,0x32,0x33,0x30,0x30,0x30,0x30,0x5A,0x30,0x17,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x03,0x13,0x0C,0x43,0x6F,0x64,
- 0x65,0x53,0x69,0x67,0x6E,0x54,0x65,0x73,0x74,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,
- 0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xB2,0xC9,0x91,0x98,0x8C,0xDC,
- 0x80,0xBC,0x16,0xBF,0xC1,0x04,0x77,0x90,0xC0,0xFD,0x8C,0xBA,0x68,0x26,0xAC,0xB7,0x20,0x68,0x41,0xED,0xC3,0x9C,0x47,0x7C,
- 0x36,0xC2,0x7B,0xE1,0x5E,0xFD,0xA9,0x99,0xF4,0x29,0x36,0x86,0x93,0x40,0x55,0x53,0x65,0x79,0xBC,0x9F,0x8F,0x6E,0x2B,0x05,
- 0x84,0xE1,0xFD,0xD2,0xEF,0xEA,0x89,0x8C,0xEC,0xF9,0x55,0xF0,0x2C,0xE5,0xA7,0x29,0xF9,0x7E,0x50,0xDC,0x9C,0xA1,0x23,0xA5,
- 0xD9,0x78,0xA1,0xE7,0x7C,0xD7,0x04,0x4F,0x11,0xAC,0x9F,0x4A,0x47,0xA1,0x1E,0xD5,0x9E,0xE7,0x5B,0xB5,0x8C,0x9C,0x67,0x7A,
- 0xD0,0xF8,0x54,0xD1,0x64,0x7F,0x39,0x48,0xB6,0xCF,0x2F,0x26,0x7D,0x7B,0x13,0x2B,0xC2,0x8F,0xA6,0x3F,0x42,0x71,0x95,0x3E,
- 0x59,0x0F,0x12,0xFA,0xC2,0x70,0x89,0xB7,0xB6,0x10,0x49,0xE0,0x7D,0x4D,0xFC,0x80,0x61,0x53,0x50,0x72,0xFD,0x46,0x35,0x51,
- 0x36,0xE6,0x06,0xA9,0x4C,0x0D,0x82,0x15,0xF6,0x5D,0xDE,0xD4,0xDB,0xE7,0x82,0x10,0x40,0xA1,0x47,0x68,0x88,0x0C,0x0A,0x80,
- 0xD1,0xE5,0x9A,0x35,0x28,0x82,0x1F,0x0F,0x80,0x5A,0x6E,0x1D,0x22,0x22,0xB3,0xA7,0xA2,0x9E,0x82,0x2D,0xC0,0x7F,0x5A,0xD0,
- 0xBA,0xB2,0xCA,0x20,0xE2,0x97,0xE9,0x72,0x41,0xB7,0xD6,0x1A,0x93,0x23,0x97,0xF0,0xA9,0x61,0xD2,0x91,0xBD,0xB6,0x6B,0x95,
- 0x12,0x67,0x16,0xAC,0x0A,0xB7,0x55,0x02,0x0D,0xA5,0xAD,0x17,0x95,0x77,0xF9,0x96,0x03,0x41,0xD3,0xE1,0x61,0x68,0xBB,0x0A,
- 0xB5,0xC4,0xEE,0x70,0x40,0x08,0x05,0xC4,0xF1,0x5D,0x02,0x03,0x01,0x00,0x01,0xA3,0x61,0x30,0x5F,0x30,0x13,0x06,0x03,0x55,
- 0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x03,0x30,0x48,0x06,0x03,0x55,0x1D,0x01,0x04,
- 0x41,0x30,0x3F,0x80,0x10,0x35,0x40,0x67,0x8F,0x7D,0x03,0x1B,0x76,0x52,0x62,0x2D,0xF5,0x21,0xF6,0x7C,0xBC,0xA1,0x19,0x30,
- 0x17,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x03,0x13,0x0C,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F,0x74,
- 0x82,0x10,0xA0,0x4B,0xEB,0xAC,0xFA,0x08,0xF2,0x8B,0x47,0xD2,0xB3,0x54,0x60,0x6C,0xE6,0x29,0x30,0x0D,0x06,0x09,0x2A,0x86,
- 0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x5F,0x8C,0x7F,0xDA,0x1D,0x21,0x7A,0x15,0xD8,0x20,
- 0x04,0x53,0x7F,0x44,0x6D,0x7B,0x57,0xBE,0x7F,0x86,0x77,0x58,0xC4,0xD4,0x80,0xC7,0x2E,0x64,0x9B,0x44,0xC5,0x2D,0x6D,0xDB,
- 0x35,0x5A,0xFE,0xA4,0xD8,0x66,0x9B,0xF7,0x6E,0xFC,0xEF,0x52,0x7B,0xC5,0x16,0xE6,0xA3,0x7D,0x59,0xB7,0x31,0x28,0xEB,0xB5,
- 0x45,0xC9,0xB1,0xD1,0x08,0x67,0xC6,0x37,0xE7,0xD7,0x2A,0xE6,0x1F,0xD9,0x6A,0xE5,0x04,0xDF,0x6A,0x9D,0x91,0xFA,0x41,0xBD,
- 0x2A,0x50,0xEA,0x99,0x24,0xA9,0x0F,0x2B,0x50,0x51,0x5F,0xD9,0x0B,0x89,0x1B,0xCB,0xDB,0x88,0xE8,0xEC,0x87,0xB0,0x16,0xCC,
- 0x43,0xEE,0x5A,0xBD,0x57,0xE2,0x46,0xA7,0x56,0x54,0x23,0x32,0x8A,0xFB,0x25,0x51,0x39,0x38,0xE6,0x87,0xF5,0x73,0x63,0xD0,
- 0x5B,0xC7,0x3F,0xFD,0x04,0x75,0x74,0x4C,0x3D,0xB5,0x31,0x22,0x7D,0xF1,0x8D,0xB4,0xE0,0xAA,0xE1,0xFF,0x8F,0xDD,0xB8,0x04,
- 0x6A,0x31,0xEE,0x30,0x2D,0x6E,0x74,0x0F,0x37,0x71,0x77,0x2B,0xB8,0x9E,0x62,0x47,0x00,0x9C,0xA5,0x82,0x2B,0x9F,0x24,0x67,
- 0x50,0x86,0x8B,0xC9,0x36,0x81,0xEB,0x44,0xC2,0xF1,0x91,0xA6,0x84,0x75,0x15,0x8F,0x22,0xDE,0xAC,0xB5,0x16,0xE3,0x96,0x74,
- 0x72,0x2F,0x15,0xD5,0xFB,0x01,0x22,0xC4,0x24,0xEE,0x3D,0xDF,0x9E,0xA9,0x0A,0x5B,0x16,0x21,0xE8,0x4A,0x8C,0x7E,0x3A,0x9C,
- 0x22,0xA0,0x49,0x60,0x97,0x1B,0x3E,0x2D,0x80,0x91,0xDB,0xF7,0x78,0x38,0x76,0x78,0x0C,0xE3,0xD4,0x27,0x77,0x69,0x96,0xE6,
- 0x41,0xC7,0x2E,0xE9,0x61,0xD6,0x31,0x82,0x01,0xC4,0x30,0x82,0x01,0xC0,0x02,0x01,0x01,0x30,0x2B,0x30,0x17,0x31,0x15,0x30,
- 0x13,0x06,0x03,0x55,0x04,0x03,0x13,0x0C,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F,0x74,0x02,0x10,0x96,0x53,
- 0x2C,0xC9,0x23,0x56,0x8A,0x87,0x42,0x30,0x3E,0xD5,0x8D,0x72,0xD5,0x25,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,
- 0x00,0xA0,0x70,0x30,0x10,0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x0C,0x31,0x02,0x30,0x00,0x30,0x19,0x06,
- 0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x03,0x31,0x0C,0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x04,
- 0x30,0x1C,0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x0B,0x31,0x0E,0x30,0x0C,0x06,0x0A,0x2B,0x06,0x01,0x04,
- 0x01,0x82,0x37,0x02,0x01,0x15,0x30,0x23,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x04,0x31,0x16,0x04,0x14,0x3D,
- 0x08,0xC8,0xA3,0xEE,0x05,0x1A,0x61,0xD9,0xFE,0x1A,0x63,0xC0,0x8A,0x6E,0x9D,0xF9,0xC3,0x13,0x98,0x30,0x0D,0x06,0x09,0x2A,
- 0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x04,0x82,0x01,0x00,0x90,0xF9,0xC0,0x7F,0x1D,0x70,0x8C,0x04,0x22,0x82,
- 0xB6,0x2D,0x48,0xBF,0x30,0x51,0x29,0xF8,0xE3,0x11,0x39,0xE0,0x64,0x23,0x72,0xE2,0x4C,0x09,0x9F,0x39,0xF2,0x6F,0xDD,0xB9,
- 0x5A,0x3D,0xEF,0xEB,0xBE,0xEC,0x3B,0xE6,0x58,0x4C,0xC9,0x4F,0xED,0xCB,0x6E,0x9D,0x67,0x8E,0x89,0x92,0x40,0x39,0xA2,0x5F,
- 0xF9,0xEF,0xD3,0xF5,0x24,0x27,0x8D,0xF7,0x3C,0x92,0x66,0x56,0xC8,0x2B,0xEA,0x04,0xA1,0x0E,0xDA,0x89,0x30,0xA7,0x01,0xD8,
- 0x0B,0xF8,0xFD,0x99,0xB6,0xC0,0x38,0xB0,0x21,0x50,0x3A,0x86,0x01,0xD0,0xF3,0x86,0x72,0xE3,0x5A,0xBB,0x2A,0x6E,0xBD,0xFB,
- 0x22,0xF9,0x42,0xD3,0x04,0xFE,0x8D,0xD8,0x79,0xD1,0xEE,0x61,0xC6,0x48,0x04,0x99,0x9A,0xA2,0x73,0xE5,0xFB,0x24,0x10,0xD5,
- 0x6B,0x71,0x80,0x0E,0x09,0xEA,0x85,0x9A,0xBD,0xBB,0xDE,0x99,0x5D,0xA3,0x18,0x4D,0xED,0x20,0x73,0x3E,0x32,0xEF,0x2C,0xAC,
- 0x5A,0x83,0x87,0x1F,0x7F,0x19,0x61,0x35,0x53,0xC1,0xAA,0x89,0x97,0xB3,0xDD,0x8D,0xA8,0x67,0x5B,0xC2,0xE2,0x09,0xB7,0xDD,
- 0x6A,0xCB,0xD5,0xBF,0xD6,0x08,0xE2,0x23,0x1A,0x41,0x9D,0xD5,0x6A,0x6B,0x8D,0x3C,0x29,0x1B,0xF1,0x3F,0x4E,0x4A,0x8F,0x29,
- 0x33,0xF9,0x1C,0x60,0xA0,0x92,0x7E,0x4F,0x35,0xB8,0xDD,0xEB,0xD1,0x68,0x1A,0x9D,0xA2,0xA6,0x97,0x1F,0x5F,0xC6,0x2C,0xFB,
- 0xCA,0xDF,0xF7,0x95,0x33,0x95,0xD4,0x79,0x5C,0x73,0x87,0x49,0x1F,0x8C,0x6E,0xCE,0x3E,0x6D,0x3D,0x2B,0x6B,0xD7,0x66,0xE9,
- 0x88,0x6F,0xF2,0x83,0xB9,0x9B,0x00,0x00
-};
-
static void test_query_object(void)
{
- WCHAR tmp_path[MAX_PATH];
BOOL ret;
CRYPT_DATA_BLOB blob;
- DWORD content_type;
/* Test the usual invalid arguments */
SetLastError(0xdeadbeef);
@@ -308,26 +188,6 @@ static void test_query_object(void)
CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED, 0,
NULL, NULL, NULL, NULL, NULL, NULL);
ok(ret, "CryptQueryObject failed: %08lx\n", GetLastError());
-
- GetEnvironmentVariableW( L"TMP", tmp_path, MAX_PATH );
- SetEnvironmentVariableW(L"TMP", L"C:\\nonexistent");
- blob.pbData = (BYTE *)signed_pe_blob;
- blob.cbData = sizeof(signed_pe_blob);
- ret = CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob,
- CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &content_type,
- NULL, NULL, NULL, NULL);
- ok(!ret, "CryptQueryObject succeeded\n");
- ok(GetLastError() == CRYPT_E_NO_MATCH, "Unexpected error %lu.\n", GetLastError());
- SetEnvironmentVariableW(L"TMP", tmp_path);
-
- blob.pbData = (BYTE *)signed_pe_blob;
- blob.cbData = sizeof(signed_pe_blob);
- ret = CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob,
- CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &content_type,
- NULL, NULL, NULL, NULL);
- ok(ret, "CryptQueryObject failed: %08lx\n", GetLastError());
- ok(content_type == CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED,
- "Got unexpected content_type %#lx.\n", content_type);
}
START_TEST(object)
diff --git a/dlls/crypt32/tests/oid.c b/dlls/crypt32/tests/oid.c
index 9520e8c5a4a..715d76b9c31 100644
--- wine/dlls/crypt32/tests/oid.c
+++ wine/dlls/crypt32/tests/oid.c
@@ -152,14 +152,14 @@ static void test_oidFunctionSet(void)
ok(ret, "CryptGetDefaultOIDDllList failed: %08lx\n", GetLastError());
if (ret)
{
- buf = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
+ buf = malloc(size * sizeof(WCHAR));
if (buf)
{
ret = CryptGetDefaultOIDDllList(set1, 0, buf, &size);
ok(ret, "CryptGetDefaultOIDDllList failed: %08lx\n",
GetLastError());
ok(!*buf, "Expected empty DLL list\n");
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
}
}
diff --git a/dlls/crypt32/tests/store.c b/dlls/crypt32/tests/store.c
index 00c2cae19e0..20d10a110f9 100644
--- wine/dlls/crypt32/tests/store.c
+++ wine/dlls/crypt32/tests/store.c
@@ -216,7 +216,7 @@ static void testMemStore(void)
ret = CertSerializeCertificateStoreElement(context, 1, NULL, &size);
ok(ret, "CertSerializeCertificateStoreElement failed: %08lx\n",
GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, size);
+ buf = malloc(size);
if (buf)
{
ret = CertSerializeCertificateStoreElement(context, 0, buf, &size);
@@ -224,7 +224,7 @@ static void testMemStore(void)
ok(size == sizeof(serializedCert), "Wrong size %ld\n", size);
ok(!memcmp(serializedCert, buf, size),
"Unexpected serialized cert\n");
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
ret = CertFreeCertificateContext(context);
@@ -311,7 +311,7 @@ static void compareStore(HCERTSTORE store, LPCSTR name, const BYTE *pb,
todo_wine_if (todo)
ok(blob.cbData == cb, "%s: expected size %ld, got %ld\n", name, cb,
blob.cbData);
- blob.pbData = HeapAlloc(GetProcessHeap(), 0, blob.cbData);
+ blob.pbData = malloc(blob.cbData);
if (blob.pbData)
{
ret = CertSaveStore(store, X509_ASN_ENCODING, CERT_STORE_SAVE_AS_STORE,
@@ -319,7 +319,7 @@ static void compareStore(HCERTSTORE store, LPCSTR name, const BYTE *pb,
ok(ret, "CertSaveStore failed: %08lx\n", GetLastError());
todo_wine_if (todo)
ok(!memcmp(pb, blob.pbData, cb), "%s: unexpected value\n", name);
- HeapFree(GetProcessHeap(), 0, blob.pbData);
+ free(blob.pbData);
}
}
@@ -1063,7 +1063,7 @@ static void testRegStore(void)
size = 0;
RegQueryValueExA(subKey, "Blob", NULL, NULL, NULL, &size);
- buf = HeapAlloc(GetProcessHeap(), 0, size);
+ buf = malloc(size);
if (buf)
{
rc = RegQueryValueExA(subKey, "Blob", NULL, NULL, buf, &size);
@@ -1092,7 +1092,7 @@ static void testRegStore(void)
hdr->cb), "Unexpected hash in cert property\n");
}
}
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
RegCloseKey(subKey);
}
@@ -2465,7 +2465,7 @@ static void testAddCertificateLink(void)
ret = CertSerializeCertificateStoreElement(linked, 0, NULL, &size);
ok(ret, "CertSerializeCertificateStoreElement failed: %08lx\n",
GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, size);
+ buf = malloc(size);
if (buf)
{
ret = CertSerializeCertificateStoreElement(linked, 0, buf, &size);
@@ -2477,7 +2477,7 @@ static void testAddCertificateLink(void)
ok(size == sizeof(serializedCert), "Wrong size %ld\n", size);
ok(!memcmp(serializedCert, buf, size),
"Unexpected serialized cert\n");
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
/* Set a friendly name on the source certificate... */
blob.pbData = (LPBYTE)L"WineTest";
@@ -2491,7 +2491,7 @@ static void testAddCertificateLink(void)
CERT_FRIENDLY_NAME_PROP_ID, NULL, &size);
ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, size);
+ buf = malloc(size);
if (buf)
{
ret = CertGetCertificateContextProperty(linked,
@@ -2500,7 +2500,7 @@ static void testAddCertificateLink(void)
GetLastError());
ok(!lstrcmpW((LPCWSTR)buf, L"WineTest"),
"unexpected friendly name\n");
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
CertFreeCertificateContext(linked);
}
@@ -2541,7 +2541,7 @@ static void testAddCertificateLink(void)
ret = CertSerializeCertificateStoreElement(linked, 0, NULL, &size);
ok(ret, "CertSerializeCertificateStoreElement failed: %08lx\n",
GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, size);
+ buf = malloc(size);
if (buf)
{
ret = CertSerializeCertificateStoreElement(linked, 0, buf, &size);
@@ -2552,7 +2552,7 @@ static void testAddCertificateLink(void)
ok(size == sizeof(serializedCert), "Wrong size %ld\n", size);
ok(!memcmp(serializedCert, buf, size),
"Unexpected serialized cert\n");
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
/* Set a friendly name on the source certificate... */
blob.pbData = (LPBYTE)L"WineTest";
@@ -2566,7 +2566,7 @@ static void testAddCertificateLink(void)
CERT_FRIENDLY_NAME_PROP_ID, NULL, &size);
ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, size);
+ buf = malloc(size);
if (buf)
{
ret = CertGetCertificateContextProperty(linked,
@@ -2574,7 +2574,7 @@ static void testAddCertificateLink(void)
ok(ret, "CertGetCertificateContextProperty failed: %08lx\n", GetLastError());
ok(!lstrcmpW((LPCWSTR)buf, L"WineTest"),
"unexpected friendly name\n");
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
CertFreeCertificateContext(linked);
}
@@ -2603,7 +2603,7 @@ static void testAddCertificateLink(void)
ret = CertSerializeCertificateStoreElement(linked, 0, NULL, &size);
ok(ret, "CertSerializeCertificateStoreElement failed: %08lx\n",
GetLastError());
- buf = HeapAlloc(GetProcessHeap(), 0, size);
+ buf = malloc(size);
if (buf)
{
ret = CertSerializeCertificateStoreElement(linked, 0, buf, &size);
@@ -2616,7 +2616,7 @@ static void testAddCertificateLink(void)
"Wrong size %ld\n", size);
ok(!memcmp(serializedCertWithFriendlyName, buf, size),
"Unexpected serialized cert\n");
- HeapFree(GetProcessHeap(), 0, buf);
+ free(buf);
}
CertFreeCertificateContext(linked);
compareStore(store2, "file store -> file store",
diff --git a/dlls/crypt32/tests/str.c b/dlls/crypt32/tests/str.c
index a94381591c0..5fb05bdb836 100644
--- wine/dlls/crypt32/tests/str.c
+++ wine/dlls/crypt32/tests/str.c
@@ -31,7 +31,6 @@ typedef struct _CertRDNAttrEncoding {
DWORD dwValueType;
CERT_RDN_VALUE_BLOB Value;
LPCSTR str;
- BOOL todo;
} CertRDNAttrEncoding, *PCertRDNAttrEncoding;
typedef struct _CertRDNAttrEncodingW {
@@ -39,7 +38,6 @@ typedef struct _CertRDNAttrEncodingW {
DWORD dwValueType;
CERT_RDN_VALUE_BLOB Value;
LPCWSTR str;
- BOOL todo;
} CertRDNAttrEncodingW, *PCertRDNAttrEncodingW;
static BYTE bin1[] = { 0x55, 0x53 };
@@ -115,6 +113,103 @@ static const BYTE cert[] =
0x65,0xd3,0xce,0xae,0x26,0x19,0x3,0x2e,0x4f,0x78,0xa5,0xa,0x97,0x7e,0x4f,0xc4,
0x91,0x8a,0xf8,0x5,0xef,0x5b,0x3b,0x49,0xbf,0x5f,0x2b};
+/*
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 5d:79:35:fd:d3:8f:6b:e2:28:3e:94:f4:14:bf:d4:b5:c2:3a:ac:38
+ Signature Algorithm: md5WithRSAEncryption
+ Issuer: C = US, ST = Minnesota, L = Minneapolis, O = CodeWeavers, CN = server_cn.org, emailAddress = test@codeweavers.com
+ Validity
+ Not Before: Apr 14 18:56:22 2022 GMT
+ Not After : Apr 11 18:56:22 2032 GMT
+ Subject: C = US, ST = Minnesota, L = Minneapolis, O = CodeWeavers, CN = server_cn.org, emailAddress = test@codeweavers.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public-Key: (1024 bit)
+ Modulus:
+...
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Alternative Name:
+ DNS:ex1.org, DNS:*.ex2.org
+ X509v3 Issuer Alternative Name:
+ DNS:ex3.org, DNS:*.ex4.org
+ Signature Algorithm: md5WithRSAEncryption
+...
+*/
+static BYTE cert_v3[] = {
+ 0x30, 0x82, 0x02, 0xdf, 0x30, 0x82, 0x02, 0x48, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x14, 0x5d, 0x79, 0x35, 0xfd, 0xd3, 0x8f, 0x6b, 0xe2, 0x28,
+ 0x3e, 0x94, 0xf4, 0x14, 0xbf, 0xd4, 0xb5, 0xc2, 0x3a, 0xac, 0x38, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04,
+ 0x05, 0x00, 0x30, 0x81, 0x8a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
+ 0x55, 0x04, 0x08, 0x0c, 0x09, 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x73, 0x6f,
+ 0x74, 0x61, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
+ 0x0b, 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x61, 0x70, 0x6f, 0x6c, 0x69, 0x73,
+ 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x43,
+ 0x6f, 0x64, 0x65, 0x57, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x31, 0x16,
+ 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0d, 0x73, 0x65, 0x72,
+ 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x23,
+ 0x30, 0x21, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
+ 0x01, 0x16, 0x14, 0x74, 0x65, 0x73, 0x74, 0x40, 0x63, 0x6f, 0x64, 0x65,
+ 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
+ 0x1e, 0x17, 0x0d, 0x32, 0x32, 0x30, 0x34, 0x31, 0x34, 0x31, 0x38, 0x35,
+ 0x36, 0x32, 0x32, 0x5a, 0x17, 0x0d, 0x33, 0x32, 0x30, 0x34, 0x31, 0x31,
+ 0x31, 0x38, 0x35, 0x36, 0x32, 0x32, 0x5a, 0x30, 0x81, 0x8a, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+ 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x09, 0x4d, 0x69,
+ 0x6e, 0x6e, 0x65, 0x73, 0x6f, 0x74, 0x61, 0x31, 0x14, 0x30, 0x12, 0x06,
+ 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0b, 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x61,
+ 0x70, 0x6f, 0x6c, 0x69, 0x73, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x0c, 0x0b, 0x43, 0x6f, 0x64, 0x65, 0x57, 0x65, 0x61, 0x76,
+ 0x65, 0x72, 0x73, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x0c, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6e, 0x2e,
+ 0x6f, 0x72, 0x67, 0x31, 0x23, 0x30, 0x21, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x14, 0x74, 0x65, 0x73, 0x74,
+ 0x40, 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81,
+ 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xcd, 0x7c, 0x05,
+ 0xba, 0xad, 0xd0, 0xb0, 0x43, 0xcc, 0x47, 0x7d, 0x87, 0xaa, 0xb5, 0x89,
+ 0x9f, 0x43, 0x94, 0xa0, 0x84, 0xc0, 0xc0, 0x5e, 0x05, 0x6d, 0x2f, 0x05,
+ 0x21, 0x6b, 0x20, 0x39, 0x88, 0x06, 0x4e, 0xce, 0x76, 0xa7, 0x24, 0x77,
+ 0x13, 0x71, 0x9b, 0x2a, 0x53, 0x04, 0x4f, 0x0f, 0xfc, 0x3f, 0x4f, 0xb1,
+ 0x4e, 0xdc, 0xed, 0x96, 0xd4, 0x55, 0xbd, 0xcf, 0x25, 0xa6, 0x7c, 0xe3,
+ 0x35, 0xbf, 0xeb, 0x30, 0xec, 0xef, 0x7f, 0x8e, 0xa1, 0xc6, 0xd3, 0xb2,
+ 0x03, 0x62, 0x0a, 0x92, 0x87, 0x17, 0x52, 0x2d, 0x45, 0x2a, 0xdc, 0xdb,
+ 0x87, 0xa5, 0x32, 0x4a, 0x78, 0x28, 0x4a, 0x51, 0xff, 0xdb, 0xd5, 0x20,
+ 0x47, 0x7e, 0xc5, 0xbe, 0x1d, 0x01, 0x55, 0x13, 0x9f, 0xfb, 0x8e, 0x39,
+ 0xd9, 0x1b, 0xe0, 0x34, 0x93, 0x43, 0x9c, 0x02, 0xa3, 0x0f, 0xb5, 0xdc,
+ 0x9d, 0x86, 0x45, 0xc5, 0x4d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x40,
+ 0x30, 0x3e, 0x30, 0x1d, 0x06, 0x03,
+ 0x55, 0x1d, 0x11, /* Subject Alternative Name OID */
+ 0x04, 0x16, 0x30, 0x14, 0x82, 0x07, 0x65, 0x78, 0x31, 0x2e, 0x6f, 0x72,
+ 0x67, 0x82, 0x09, 0x2a, 0x2e, 0x65, 0x78, 0x32, 0x2e, 0x6f, 0x72, 0x67,
+ 0x30, 0x1d, 0x06, 0x03,
+ 0x55, 0x1d, 0x12, /* Issuer Alternative Name OID */
+ 0x04, 0x16, 0x30, 0x14, 0x82, 0x07, 0x65, 0x78, 0x33, 0x2e, 0x6f, 0x72,
+ 0x67, 0x82, 0x09, 0x2a, 0x2e, 0x65, 0x78, 0x34, 0x2e, 0x6f, 0x72, 0x67,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x04, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xcc, 0xa3, 0x75, 0x67, 0x61,
+ 0x63, 0x1d, 0x99, 0x16, 0xc6, 0x93, 0x35, 0xa4, 0x31, 0xb6, 0x05, 0x05,
+ 0x77, 0x12, 0x15, 0x16, 0x78, 0xb3, 0xba, 0x6e, 0xde, 0xfc, 0x73, 0x7c,
+ 0x5c, 0xdd, 0xdf, 0x92, 0xde, 0xa0, 0x86, 0xff, 0x77, 0x60, 0x99, 0x8f,
+ 0x4a, 0x40, 0xa8, 0x6a, 0xdb, 0x6f, 0x30, 0xe5, 0xce, 0x82, 0x2f, 0xf7,
+ 0x09, 0x17, 0xb2, 0xd3, 0x3a, 0x29, 0x9a, 0xd0, 0x73, 0x9c, 0x44, 0xa2,
+ 0x19, 0xf3, 0x1d, 0x16, 0x1a, 0x45, 0x2c, 0x4b, 0x94, 0xf1, 0xb8, 0xb6,
+ 0xc9, 0x82, 0x6c, 0x1f, 0xae, 0xbc, 0xd1, 0xbe, 0x78, 0xc9, 0x23, 0xf5,
+ 0x51, 0x6c, 0x90, 0xbf, 0xa3, 0x5c, 0xa1, 0x3a, 0xd8, 0xe3, 0xcf, 0x82,
+ 0x31, 0x78, 0x2b, 0xda, 0x99, 0xff, 0x23, 0x5b, 0xea, 0x59, 0xe0, 0x6d,
+ 0xd1, 0x30, 0xfd, 0x96, 0x6a, 0x4d, 0x36, 0x72, 0x96, 0xd7, 0x4f, 0x01,
+ 0xa9, 0x4d, 0x8f
+};
+
+#define CERT_V3_SAN_OID_OFFSET 534
+#define CERT_V3_IAN_OID_OFFSET 565
+
static char issuerStr[] =
"US, Minnesota, Minneapolis, CodeWeavers, Wine Development, localhost, aric@codeweavers.com";
static char issuerStrSemicolon[] =
@@ -134,33 +229,34 @@ static void test_CertRDNValueToStrA(void)
{
CertRDNAttrEncoding attrs[] = {
{ "2.5.4.6", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin1), bin1 }, "US", FALSE },
+ { sizeof(bin1), bin1 }, "US" },
{ "2.5.4.8", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin2), bin2 }, "Minnesota", FALSE },
+ { sizeof(bin2), bin2 }, "Minnesota" },
{ "2.5.4.7", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin3), bin3 }, "Minneapolis", FALSE },
+ { sizeof(bin3), bin3 }, "Minneapolis" },
{ "2.5.4.10", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin4), bin4 }, "CodeWeavers", FALSE },
+ { sizeof(bin4), bin4 }, "CodeWeavers" },
{ "2.5.4.11", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin5), bin5 }, "Wine Development", FALSE },
+ { sizeof(bin5), bin5 }, "Wine Development" },
{ "2.5.4.3", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin6), bin6 }, "localhost", FALSE },
+ { sizeof(bin6), bin6 }, "localhost" },
{ "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING,
- { sizeof(bin7), bin7 }, "aric@codeweavers.com", FALSE },
+ { sizeof(bin7), bin7 }, "aric@codeweavers.com" },
{ "0", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin9), bin9 }, "abc\"def", FALSE },
+ { sizeof(bin9), bin9 }, "abc\"def" },
{ "0", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin10), bin10 }, "abc'def", FALSE },
+ { sizeof(bin10), bin10 }, "abc'def" },
{ "0", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin11), bin11 }, "abc, def", FALSE },
+ { sizeof(bin11), bin11 }, "abc, def" },
{ "0", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin12), bin12 }, " abc ", FALSE },
+ { sizeof(bin12), bin12 }, " abc " },
{ "0", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin13), bin13 }, "\"def\"", FALSE },
+ { sizeof(bin13), bin13 }, "\"def\"" },
{ "0", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin14), bin14 }, "1;3", FALSE },
+ { sizeof(bin14), bin14 }, "1;3" },
};
- DWORD i, ret;
+ unsigned int i;
+ DWORD ret, len;
char buffer[2000];
CERT_RDN_VALUE_BLOB blob = { 0, NULL };
static const char ePKI[] = "ePKI Root Certification Authority";
@@ -178,15 +274,21 @@ static void test_CertRDNValueToStrA(void)
for (i = 0; i < ARRAY_SIZE(attrs); i++)
{
- ret = CertRDNValueToStrA(attrs[i].dwValueType, &attrs[i].Value,
+ len = CertRDNValueToStrA(attrs[i].dwValueType, &attrs[i].Value,
buffer, sizeof(buffer));
- todo_wine_if (attrs[i].todo)
- {
- ok(ret == strlen(attrs[i].str) + 1, "Expected length %d, got %ld\n",
- lstrlenA(attrs[i].str) + 1, ret);
- ok(!strcmp(buffer, attrs[i].str), "Expected %s, got %s\n",
- attrs[i].str, buffer);
- }
+ ok(len == strlen(attrs[i].str) + 1, "Expected length %d, got %ld\n",
+ lstrlenA(attrs[i].str) + 1, ret);
+ ok(!strcmp(buffer, attrs[i].str), "Expected %s, got %s\n",
+ attrs[i].str, buffer);
+ memset(buffer, 0xcc, sizeof(buffer));
+ ret = CertRDNValueToStrA(attrs[i].dwValueType, &attrs[i].Value, buffer, len - 1);
+ ok(ret == 1, "Unexpected ret %lu, expected 1, test %u.\n", ret, i);
+ ok(!buffer[0], "Unexpected value %#x, test %u.\n", buffer[0], i);
+ ok(!strncmp(buffer + 1, attrs[i].str + 1, len - 2), "Strings do not match, test %u.\n", i);
+ memset(buffer, 0xcc, sizeof(buffer));
+ ret = CertRDNValueToStrA(attrs[i].dwValueType, &attrs[i].Value, buffer, 0);
+ ok(ret == len, "Unexpected ret %lu, expected %lu, test %u.\n", ret, len, i);
+ ok((unsigned char)buffer[0] == 0xcc, "Unexpected value %#x, test %u.\n", buffer[0], i);
}
blob.pbData = bin8;
blob.cbData = sizeof(bin8);
@@ -202,33 +304,34 @@ static void test_CertRDNValueToStrW(void)
static const WCHAR ePKIW[] = L"ePKI Root Certification Authority";
CertRDNAttrEncodingW attrs[] = {
{ "2.5.4.6", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin1), bin1 }, L"US", FALSE },
+ { sizeof(bin1), bin1 }, L"US" },
{ "2.5.4.8", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin2), bin2 }, L"Minnesota", FALSE },
+ { sizeof(bin2), bin2 }, L"Minnesota" },
{ "2.5.4.7", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin3), bin3 }, L"Minneapolis", FALSE },
+ { sizeof(bin3), bin3 }, L"Minneapolis" },
{ "2.5.4.10", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin4), bin4 }, L"CodeWeavers", FALSE },
+ { sizeof(bin4), bin4 }, L"CodeWeavers" },
{ "2.5.4.11", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin5), bin5 }, L"Wine Development", FALSE },
+ { sizeof(bin5), bin5 }, L"Wine Development" },
{ "2.5.4.3", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin6), bin6 }, L"localhost", FALSE },
+ { sizeof(bin6), bin6 }, L"localhost" },
{ "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING,
- { sizeof(bin7), bin7 }, L"aric@codeweavers.com", FALSE },
+ { sizeof(bin7), bin7 }, L"aric@codeweavers.com" },
{ "0", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin9), bin9 }, L"abc\"def", FALSE },
+ { sizeof(bin9), bin9 }, L"abc\"def" },
{ "0", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin10), bin10 }, L"abc'def", FALSE },
+ { sizeof(bin10), bin10 }, L"abc'def" },
{ "0", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin11), bin11 }, L"abc, def", FALSE },
+ { sizeof(bin11), bin11 }, L"abc, def" },
{ "0", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin12), bin12 }, L" abc ", FALSE },
+ { sizeof(bin12), bin12 }, L" abc " },
{ "0", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin13), bin13 }, L"\"def\"", FALSE },
+ { sizeof(bin13), bin13 }, L"\"def\"" },
{ "0", CERT_RDN_PRINTABLE_STRING,
- { sizeof(bin14), bin14 }, L"1;3", FALSE },
+ { sizeof(bin14), bin14 }, L"1;3" },
};
- DWORD i, ret;
+ unsigned int i;
+ DWORD ret, len;
WCHAR buffer[2000];
CERT_RDN_VALUE_BLOB blob = { 0, NULL };
@@ -245,14 +348,20 @@ static void test_CertRDNValueToStrW(void)
for (i = 0; i < ARRAY_SIZE(attrs); i++)
{
- ret = CertRDNValueToStrW(attrs[i].dwValueType, &attrs[i].Value, buffer, ARRAY_SIZE(buffer));
- todo_wine_if (attrs[i].todo)
- {
- ok(ret == lstrlenW(attrs[i].str) + 1,
- "Expected length %d, got %ld\n", lstrlenW(attrs[i].str) + 1, ret);
- ok(!lstrcmpW(buffer, attrs[i].str), "Expected %s, got %s\n",
- wine_dbgstr_w(attrs[i].str), wine_dbgstr_w(buffer));
- }
+ len = CertRDNValueToStrW(attrs[i].dwValueType, &attrs[i].Value, buffer, ARRAY_SIZE(buffer));
+ ok(len == lstrlenW(attrs[i].str) + 1,
+ "Expected length %d, got %ld\n", lstrlenW(attrs[i].str) + 1, ret);
+ ok(!lstrcmpW(buffer, attrs[i].str), "Expected %s, got %s\n",
+ wine_dbgstr_w(attrs[i].str), wine_dbgstr_w(buffer));
+ memset(buffer, 0xcc, sizeof(buffer));
+ ret = CertRDNValueToStrW(attrs[i].dwValueType, &attrs[i].Value, buffer, len - 1);
+ ok(ret == 1, "Unexpected ret %lu, expected 1, test %u.\n", ret, i);
+ ok(!buffer[0], "Unexpected value %#x, test %u.\n", buffer[0], i);
+ ok(buffer[1] == 0xcccc, "Unexpected value %#x, test %u.\n", buffer[1], i);
+ memset(buffer, 0xcc, sizeof(buffer));
+ ret = CertRDNValueToStrW(attrs[i].dwValueType, &attrs[i].Value, buffer, 0);
+ ok(ret == len, "Unexpected ret %lu, expected %lu, test %u.\n", ret, len, i);
+ ok(buffer[0] == 0xcccc, "Unexpected value %#x, test %u.\n", buffer[0], i);
}
blob.pbData = bin8;
blob.cbData = sizeof(bin8);
@@ -264,24 +373,27 @@ static void test_CertRDNValueToStrW(void)
wine_dbgstr_w(ePKIW), wine_dbgstr_w(buffer));
}
-static void test_NameToStrConversionA(PCERT_NAME_BLOB pName, DWORD dwStrType,
- LPCSTR expected, BOOL todo)
+#define test_NameToStrConversionA(a, b, c) test_NameToStrConversionA_(__LINE__, a, b, c)
+static void test_NameToStrConversionA_(unsigned int line, PCERT_NAME_BLOB pName, DWORD dwStrType, LPCSTR expected)
{
- char buffer[2000] = { 0 };
- DWORD i;
-
- i = CertNameToStrA(X509_ASN_ENCODING, pName, dwStrType, NULL, 0);
- todo_wine_if (todo)
- ok(i == strlen(expected) + 1, "Expected %d chars, got %ld\n",
- lstrlenA(expected) + 1, i);
- i = CertNameToStrA(X509_ASN_ENCODING,pName, dwStrType, buffer,
- sizeof(buffer));
- todo_wine_if (todo)
- ok(i == strlen(expected) + 1, "Expected %d chars, got %ld\n",
- lstrlenA(expected) + 1, i);
- todo_wine_if (todo)
- ok(!strcmp(buffer, expected), "Expected %s, got %s\n", expected,
- buffer);
+ char buffer[2000];
+ DWORD len, retlen;
+
+ len = CertNameToStrA(X509_ASN_ENCODING, pName, dwStrType, NULL, 0);
+ ok(len == strlen(expected) + 1, "line %u: Expected %d chars, got %ld.\n", line, lstrlenA(expected) + 1, len);
+ len = CertNameToStrA(X509_ASN_ENCODING,pName, dwStrType, buffer, sizeof(buffer));
+ ok(len == strlen(expected) + 1, "line %u: Expected %d chars, got %ld.\n", line, lstrlenA(expected) + 1, len);
+ ok(!strcmp(buffer, expected), "line %u: Expected %s, got %s.\n", line, expected, buffer);
+
+ memset(buffer, 0xcc, sizeof(buffer));
+ retlen = CertNameToStrA(X509_ASN_ENCODING, pName, dwStrType, buffer, len - 1);
+ ok(retlen == 1, "line %u: expected 1, got %lu\n", line, retlen);
+ ok(!buffer[0], "line %u: string is not zero terminated.\n", line);
+
+ memset(buffer, 0xcc, sizeof(buffer));
+ retlen = CertNameToStrA(X509_ASN_ENCODING, pName, dwStrType, buffer, 0);
+ ok(retlen == len, "line %u: expected %lu chars, got %lu\n", line, len - 1, retlen);
+ ok((unsigned char)buffer[0] == 0xcc, "line %u: got %s\n", line, wine_dbgstr_a(buffer));
}
static BYTE encodedSimpleCN[] = {
@@ -354,98 +466,98 @@ static void test_CertNameToStrA(void)
"Expected positive return and ERROR_SUCCESS, got %ld - %08lx\n",
ret, GetLastError());
+ test_NameToStrConversionA(&context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, issuerStr);
test_NameToStrConversionA(&context->pCertInfo->Issuer,
- CERT_SIMPLE_NAME_STR, issuerStr, FALSE);
- test_NameToStrConversionA(&context->pCertInfo->Issuer,
- CERT_SIMPLE_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG,
- issuerStrSemicolon, FALSE);
+ CERT_SIMPLE_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG, issuerStrSemicolon);
test_NameToStrConversionA(&context->pCertInfo->Issuer,
- CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
- issuerStrCRLF, FALSE);
- test_NameToStrConversionA(&context->pCertInfo->Subject,
- CERT_OID_NAME_STR, subjectStr, FALSE);
+ CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG, issuerStrCRLF);
+ test_NameToStrConversionA(&context->pCertInfo->Subject, CERT_OID_NAME_STR, subjectStr);
test_NameToStrConversionA(&context->pCertInfo->Subject,
- CERT_OID_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG,
- subjectStrSemicolon, FALSE);
+ CERT_OID_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG, subjectStrSemicolon);
test_NameToStrConversionA(&context->pCertInfo->Subject,
- CERT_OID_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
- subjectStrCRLF, FALSE);
+ CERT_OID_NAME_STR | CERT_NAME_STR_CRLF_FLAG, subjectStrCRLF);
test_NameToStrConversionA(&context->pCertInfo->Subject,
- CERT_X500_NAME_STR, x500SubjectStr, FALSE);
+ CERT_X500_NAME_STR, x500SubjectStr);
test_NameToStrConversionA(&context->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG | CERT_NAME_STR_REVERSE_FLAG,
- x500SubjectStrSemicolonReverse, FALSE);
+ x500SubjectStrSemicolonReverse);
CertFreeCertificateContext(context);
}
blob.pbData = encodedSimpleCN;
blob.cbData = sizeof(encodedSimpleCN);
- test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=1", FALSE);
+ test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=1");
blob.pbData = encodedSingleQuotedCN;
blob.cbData = sizeof(encodedSingleQuotedCN);
- test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN='1'", FALSE);
- test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "'1'", FALSE);
+ test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN='1'");
+ test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "'1'");
blob.pbData = encodedSpacedCN;
blob.cbData = sizeof(encodedSpacedCN);
- test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\" 1 \"", FALSE);
- test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\" 1 \"", FALSE);
+ test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\" 1 \"");
+ test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\" 1 \"");
blob.pbData = encodedQuotedCN;
blob.cbData = sizeof(encodedQuotedCN);
- test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"\"\"1\"\"\"",
- FALSE);
- test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"\"\"1\"\"\"",
- FALSE);
+ test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"\"\"1\"\"\"");
+ test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"\"\"1\"\"\"");
blob.pbData = encodedMultipleAttrCN;
blob.cbData = sizeof(encodedMultipleAttrCN);
- test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"1+2\"", FALSE);
- test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"1+2\"", FALSE);
+ test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"1+2\"");
+ test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"1+2\"");
blob.pbData = encodedCommaCN;
blob.cbData = sizeof(encodedCommaCN);
- test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"a,b\"", FALSE);
- test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"a,b\"", FALSE);
+ test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"a,b\"");
+ test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"a,b\"");
blob.pbData = encodedEqualCN;
blob.cbData = sizeof(encodedEqualCN);
- test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"a=b\"", FALSE);
- test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"a=b\"", FALSE);
+ test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"a=b\"");
+ test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"a=b\"");
blob.pbData = encodedLessThanCN;
blob.cbData = sizeof(encodedLessThanCN);
- test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"<\"", FALSE);
- test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"<\"", FALSE);
+ test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"<\"");
+ test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"<\"");
blob.pbData = encodedGreaterThanCN;
blob.cbData = sizeof(encodedGreaterThanCN);
- test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\">\"", FALSE);
- test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\">\"", FALSE);
+ test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\">\"");
+ test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\">\"");
blob.pbData = encodedHashCN;
blob.cbData = sizeof(encodedHashCN);
- test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"#\"", FALSE);
- test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"#\"", FALSE);
+ test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"#\"");
+ test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"#\"");
blob.pbData = encodedSemiCN;
blob.cbData = sizeof(encodedSemiCN);
- test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\";\"", FALSE);
- test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\";\"", FALSE);
+ test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\";\"");
+ test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\";\"");
blob.pbData = encodedNewlineCN;
blob.cbData = sizeof(encodedNewlineCN);
- test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"a\nb\"", FALSE);
- test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"a\nb\"", FALSE);
+ test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"a\nb\"");
+ test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"a\nb\"");
}
-static void test_NameToStrConversionW(PCERT_NAME_BLOB pName, DWORD dwStrType,
- LPCWSTR expected, BOOL todo)
+#define test_NameToStrConversionW(a, b, c) test_NameToStrConversionW_(__LINE__, a, b, c)
+static void test_NameToStrConversionW_(unsigned int line, PCERT_NAME_BLOB pName, DWORD dwStrType, LPCWSTR expected)
{
- WCHAR buffer[2000] = { 0 };
- DWORD i;
-
- i = CertNameToStrW(X509_ASN_ENCODING,pName, dwStrType, NULL, 0);
- todo_wine_if (todo)
- ok(i == lstrlenW(expected) + 1, "Expected %d chars, got %ld\n",
- lstrlenW(expected) + 1, i);
- i = CertNameToStrW(X509_ASN_ENCODING,pName, dwStrType, buffer, ARRAY_SIZE(buffer));
- todo_wine_if (todo)
- ok(i == lstrlenW(expected) + 1, "Expected %d chars, got %ld\n",
- lstrlenW(expected) + 1, i);
- todo_wine_if (todo)
- ok(!lstrcmpW(buffer, expected), "Expected %s, got %s\n",
- wine_dbgstr_w(expected), wine_dbgstr_w(buffer));
+ DWORD len, retlen, expected_len;
+ WCHAR buffer[2000];
+
+ expected_len = wcslen(expected) + 1;
+ memset(buffer, 0xcc, sizeof(buffer));
+ len = CertNameToStrW(X509_ASN_ENCODING, pName, dwStrType, NULL, 0);
+ ok(len == expected_len, "line %u: expected %lu chars, got %lu\n", line, expected_len, len);
+ retlen = CertNameToStrW(X509_ASN_ENCODING, pName, dwStrType, buffer, ARRAY_SIZE(buffer));
+ ok(retlen == len, "line %u: expected %lu chars, got %lu.\n", line, len, retlen);
+ ok(!wcscmp(buffer, expected), "Expected %s, got %s\n", wine_dbgstr_w(expected), wine_dbgstr_w(buffer));
+
+ memset(buffer, 0xcc, sizeof(buffer));
+ retlen = CertNameToStrW(X509_ASN_ENCODING, pName, dwStrType, buffer, len - 1);
+ ok(retlen == len - 1, "line %u: expected %lu chars, got %lu\n", line, len - 1, retlen);
+ ok(!wcsncmp(buffer, expected, retlen - 1), "line %u: expected %s, got %s\n",
+ line, wine_dbgstr_w(expected), wine_dbgstr_w(buffer));
+ ok(!buffer[retlen - 1], "line %u: string is not zero terminated.\n", line);
+
+ memset(buffer, 0xcc, sizeof(buffer));
+ retlen = CertNameToStrW(X509_ASN_ENCODING, pName, dwStrType, buffer, 0);
+ ok(retlen == len, "line %u: expected %lu chars, got %lu\n", line, len - 1, retlen);
+ ok(buffer[0] == 0xcccc, "line %u: got %s\n", line, wine_dbgstr_w(buffer));
}
static void test_CertNameToStrW(void)
@@ -479,95 +591,79 @@ static void test_CertNameToStrW(void)
test_NameToStrConversionW(&context->pCertInfo->Issuer,
CERT_SIMPLE_NAME_STR,
- L"US, Minnesota, Minneapolis, CodeWeavers, Wine Development, localhost, aric@codeweavers.com", FALSE);
+ L"US, Minnesota, Minneapolis, CodeWeavers, Wine Development, localhost, aric@codeweavers.com");
test_NameToStrConversionW(&context->pCertInfo->Issuer,
CERT_SIMPLE_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG,
- L"US; Minnesota; Minneapolis; CodeWeavers; Wine Development; localhost; aric@codeweavers.com", FALSE);
+ L"US; Minnesota; Minneapolis; CodeWeavers; Wine Development; localhost; aric@codeweavers.com");
test_NameToStrConversionW(&context->pCertInfo->Issuer,
CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
- L"US\r\nMinnesota\r\nMinneapolis\r\nCodeWeavers\r\nWine Development\r\nlocalhost\r\naric@codeweavers.com",
- FALSE);
+ L"US\r\nMinnesota\r\nMinneapolis\r\nCodeWeavers\r\nWine Development\r\nlocalhost\r\naric@codeweavers.com");
test_NameToStrConversionW(&context->pCertInfo->Subject,
CERT_OID_NAME_STR,
L"2.5.4.6=US, 2.5.4.8=Minnesota, 2.5.4.7=Minneapolis, 2.5.4.10=CodeWeavers, 2.5.4.11=Wine Development,"
- " 2.5.4.3=localhost, 1.2.840.113549.1.9.1=aric@codeweavers.com", FALSE);
+ " 2.5.4.3=localhost, 1.2.840.113549.1.9.1=aric@codeweavers.com");
test_NameToStrConversionW(&context->pCertInfo->Subject,
CERT_OID_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG,
L"2.5.4.6=US; 2.5.4.8=Minnesota; 2.5.4.7=Minneapolis; 2.5.4.10=CodeWeavers; 2.5.4.11=Wine Development;"
- " 2.5.4.3=localhost; 1.2.840.113549.1.9.1=aric@codeweavers.com", FALSE);
+ " 2.5.4.3=localhost; 1.2.840.113549.1.9.1=aric@codeweavers.com");
test_NameToStrConversionW(&context->pCertInfo->Subject,
CERT_OID_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
L"2.5.4.6=US\r\n2.5.4.8=Minnesota\r\n2.5.4.7=Minneapolis\r\n2.5.4.10=CodeWeavers\r\n2.5.4.11=Wine "
- "Development\r\n2.5.4.3=localhost\r\n1.2.840.113549.1.9.1=aric@codeweavers.com", FALSE);
+ "Development\r\n2.5.4.3=localhost\r\n1.2.840.113549.1.9.1=aric@codeweavers.com");
test_NameToStrConversionW(&context->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG | CERT_NAME_STR_REVERSE_FLAG,
L"E=aric@codeweavers.com; CN=localhost; OU=Wine Development; O=CodeWeavers; L=Minneapolis; S=Minnesota; "
- "C=US", FALSE);
+ "C=US");
CertFreeCertificateContext(context);
}
blob.pbData = encodedSimpleCN;
blob.cbData = sizeof(encodedSimpleCN);
- test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=1", FALSE);
+ test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=1");
blob.pbData = encodedSingleQuotedCN;
blob.cbData = sizeof(encodedSingleQuotedCN);
- test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN='1'",
- FALSE);
- test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR,
- L"'1'", FALSE);
+ test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN='1'");
+ test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"'1'");
blob.pbData = encodedSpacedCN;
blob.cbData = sizeof(encodedSpacedCN);
- test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\" 1 \"", FALSE);
- test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\" 1 \"",
- FALSE);
+ test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\" 1 \"");
+ test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\" 1 \"");
blob.pbData = encodedQuotedCN;
blob.cbData = sizeof(encodedQuotedCN);
- test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"\"\"1\"\"\"",
- FALSE);
- test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"\"\"1\"\"\"",
- FALSE);
+ test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"\"\"1\"\"\"");
+ test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"\"\"1\"\"\"");
blob.pbData = encodedMultipleAttrCN;
blob.cbData = sizeof(encodedMultipleAttrCN);
- test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"1+2\"",
- FALSE);
- test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR,
- L"\"1+2\"", FALSE);
+ test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"1+2\"");
+ test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"1+2\"");
blob.pbData = encodedCommaCN;
blob.cbData = sizeof(encodedCommaCN);
- test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"a,b\"", FALSE);
- test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"a,b\"",
- FALSE);
+ test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"a,b\"");
+ test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"a,b\"");
blob.pbData = encodedEqualCN;
blob.cbData = sizeof(encodedEqualCN);
- test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"a=b\"", FALSE);
- test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"a=b\"",
- FALSE);
+ test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"a=b\"");
+ test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"a=b\"");
blob.pbData = encodedLessThanCN;
blob.cbData = sizeof(encodedLessThanCN);
- test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"<\"", FALSE);
- test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"<\"",
- FALSE);
+ test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"<\"");
+ test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"<\"");
blob.pbData = encodedGreaterThanCN;
blob.cbData = sizeof(encodedGreaterThanCN);
- test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\">\"",
- FALSE);
- test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR,
- L"\">\"", FALSE);
+ test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\">\"");
+ test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\">\"");
blob.pbData = encodedHashCN;
blob.cbData = sizeof(encodedHashCN);
- test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"#\"", FALSE);
- test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"#\"",
- FALSE);
+ test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"#\"");
+ test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"#\"");
blob.pbData = encodedSemiCN;
blob.cbData = sizeof(encodedSemiCN);
- test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\";\"", FALSE);
- test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\";\"",
- FALSE);
+ test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\";\"");
+ test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\";\"");
blob.pbData = encodedNewlineCN;
blob.cbData = sizeof(encodedNewlineCN);
- test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"a\nb\"", FALSE);
- test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"a\nb\"",
- FALSE);
+ test_NameToStrConversionW(&blob, CERT_X500_NAME_STR, L"CN=\"a\nb\"");
+ test_NameToStrConversionW(&blob, CERT_SIMPLE_NAME_STR, L"\"a\nb\"");
}
struct StrToNameA
@@ -747,153 +843,140 @@ static void test_CertStrToNameW(void)
}
}
-static void test_CertGetNameStringA(void)
+#define test_CertGetNameString_value(a, b, c, d, e) test_CertGetNameString_value_(__LINE__, a, b, c, d, e)
+static void test_CertGetNameString_value_(unsigned int line, PCCERT_CONTEXT context, DWORD type, DWORD flags,
+ void *type_para, const char *expected)
{
+ DWORD len, retlen, expected_len;
+ WCHAR expectedW[512];
+ WCHAR strW[512];
+ char str[512];
+
+ expected_len = 0;
+ while(expected[expected_len])
+ {
+ while((expectedW[expected_len] = expected[expected_len]))
+ ++expected_len;
+ if (!(flags & CERT_NAME_SEARCH_ALL_NAMES_FLAG))
+ break;
+ expectedW[expected_len++] = 0;
+ }
+ expectedW[expected_len++] = 0;
+
+ len = CertGetNameStringA(context, type, flags, type_para, NULL, 0);
+ ok(len == expected_len, "line %u: unexpected length %ld, expected %ld.\n", line, len, expected_len);
+ memset(str, 0xcc, len);
+ retlen = CertGetNameStringA(context, type, flags, type_para, str, len);
+ ok(retlen == len, "line %u: unexpected len %lu, expected %lu.\n", line, retlen, len);
+ ok(!memcmp(str, expected, expected_len), "line %u: unexpected value %s.\n", line, debugstr_an(str, expected_len));
+ str[0] = str[1] = 0xcc;
+ retlen = CertGetNameStringA(context, type, flags, type_para, str, len - 1);
+ ok(retlen == 1, "line %u: Unexpected len %lu, expected 1.\n", line, retlen);
+ if (len == 1) return;
+ ok(!str[0], "line %u: unexpected str[0] %#x.\n", line, str[0]);
+ ok(str[1] == expected[1], "line %u: unexpected str[1] %#x.\n", line, str[1]);
+ ok(!memcmp(str + 1, expected + 1, len - 2),
+ "line %u: str %s, string data mismatch.\n", line, debugstr_a(str + 1));
+ retlen = CertGetNameStringA(context, type, flags, type_para, str, 0);
+ ok(retlen == len, "line %u: Unexpected len %lu, expected 1.\n", line, retlen);
+
+ memset(strW, 0xcc, len * sizeof(*strW));
+ retlen = CertGetNameStringW(context, type, flags, type_para, strW, len);
+ ok(retlen == expected_len, "line %u: unexpected len %lu, expected %lu.\n", line, retlen, expected_len);
+ ok(!memcmp(strW, expectedW, len * sizeof(*strW)), "line %u: unexpected value %s.\n", line, debugstr_wn(strW, len));
+ strW[0] = strW[1] = 0xcccc;
+ retlen = CertGetNameStringW(context, type, flags, type_para, strW, len - 1);
+ ok(retlen == len - 1, "line %u: unexpected len %lu, expected %lu.\n", line, retlen, len - 1);
+ if (flags & CERT_NAME_SEARCH_ALL_NAMES_FLAG)
+ {
+ ok(!memcmp(strW, expectedW, (retlen - 2) * sizeof(*strW)),
+ "line %u: str %s, string data mismatch.\n", line, debugstr_wn(strW, retlen - 2));
+ ok(!strW[retlen - 2], "line %u: string is not zero terminated.\n", line);
+ ok(!strW[retlen - 1], "line %u: string sequence is not zero terminated.\n", line);
+
+ retlen = CertGetNameStringW(context, type, flags, type_para, strW, 1);
+ ok(retlen == 1, "line %u: unexpected len %lu, expected %lu.\n", line, retlen, len - 1);
+ ok(!strW[retlen - 1], "line %u: string sequence is not zero terminated.\n", line);
+ }
+ else
+ {
+ ok(!memcmp(strW, expectedW, (retlen - 1) * sizeof(*strW)),
+ "line %u: str %s, string data mismatch.\n", line, debugstr_wn(strW, retlen - 1));
+ ok(!strW[retlen - 1], "line %u: string is not zero terminated.\n", line);
+ }
+ retlen = CertGetNameStringA(context, type, flags, type_para, NULL, len - 1);
+ ok(retlen == len, "line %u: unexpected len %lu, expected %lu\n", line, retlen, len);
+ retlen = CertGetNameStringW(context, type, flags, type_para, NULL, len - 1);
+ ok(retlen == len, "line %u: unexpected len %lu, expected %lu\n", line, retlen, len);
+}
+
+static void test_CertGetNameString(void)
+{
+ static const char aric[] = "aric@codeweavers.com";
+ static const char localhost[] = "localhost";
PCCERT_CONTEXT context;
+ DWORD len, type;
context = CertCreateCertificateContext(X509_ASN_ENCODING, cert,
sizeof(cert));
- ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
- GetLastError());
- if (context)
- {
- static const char aric[] = "aric@codeweavers.com";
- static const char localhost[] = "localhost";
- DWORD len, type;
- LPSTR str;
-
- /* Bad string types/types missing from the cert */
- len = CertGetNameStringA(NULL, 0, 0, NULL, NULL, 0);
- ok(len == 1, "expected 1, got %ld\n", len);
- len = CertGetNameStringA(context, 0, 0, NULL, NULL, 0);
- ok(len == 1, "expected 1, got %ld\n", len);
- len = CertGetNameStringA(context, CERT_NAME_URL_TYPE, 0, NULL, NULL,
- 0);
- ok(len == 1, "expected 1, got %ld\n", len);
-
- len = CertGetNameStringA(context, CERT_NAME_EMAIL_TYPE, 0, NULL, NULL,
- 0);
- ok(len == strlen(aric) + 1, "unexpected length %ld\n", len);
- str = HeapAlloc(GetProcessHeap(), 0, len);
- if (str)
- {
- len = CertGetNameStringA(context, CERT_NAME_EMAIL_TYPE, 0, NULL,
- str, len);
- ok(!strcmp(str, aric), "unexpected value %s\n", str);
- HeapFree(GetProcessHeap(), 0, str);
- }
-
- len = CertGetNameStringA(context, CERT_NAME_RDN_TYPE, 0, NULL, NULL,
- 0);
- ok(len == strlen(issuerStr) + 1, "unexpected length %ld\n", len);
- str = HeapAlloc(GetProcessHeap(), 0, len);
- if (str)
- {
- len = CertGetNameStringA(context, CERT_NAME_RDN_TYPE, 0, NULL,
- str, len);
- ok(!strcmp(str, issuerStr), "unexpected value %s\n", str);
- HeapFree(GetProcessHeap(), 0, str);
- }
- type = 0;
- len = CertGetNameStringA(context, CERT_NAME_RDN_TYPE, 0, &type, NULL,
- 0);
- ok(len == strlen(issuerStr) + 1, "unexpected length %ld\n", len);
- str = HeapAlloc(GetProcessHeap(), 0, len);
- if (str)
- {
- len = CertGetNameStringA(context, CERT_NAME_RDN_TYPE, 0, &type,
- str, len);
- ok(!strcmp(str, issuerStr), "unexpected value %s\n", str);
- HeapFree(GetProcessHeap(), 0, str);
- }
- type = CERT_OID_NAME_STR;
- len = CertGetNameStringA(context, CERT_NAME_RDN_TYPE, 0, &type, NULL,
- 0);
- ok(len == strlen(subjectStr) + 1, "unexpected length %ld\n", len);
- str = HeapAlloc(GetProcessHeap(), 0, len);
- if (str)
- {
- len = CertGetNameStringA(context, CERT_NAME_RDN_TYPE, 0, &type,
- str, len);
- ok(!strcmp(str, subjectStr), "unexpected value %s\n", str);
- HeapFree(GetProcessHeap(), 0, str);
- }
-
- len = CertGetNameStringA(context, CERT_NAME_ATTR_TYPE, 0, NULL, NULL,
- 0);
- ok(len == strlen(aric) + 1, "unexpected length %ld\n", len);
- str = HeapAlloc(GetProcessHeap(), 0, len);
- if (str)
- {
- len = CertGetNameStringA(context, CERT_NAME_ATTR_TYPE, 0, NULL,
- str, len);
- ok(!strcmp(str, aric), "unexpected value %s\n", str);
- HeapFree(GetProcessHeap(), 0, str);
- }
- len = CertGetNameStringA(context, CERT_NAME_ATTR_TYPE, 0,
- (void *)szOID_RSA_emailAddr, NULL, 0);
- ok(len == strlen(aric) + 1, "unexpected length %ld\n", len);
- str = HeapAlloc(GetProcessHeap(), 0, len);
- if (str)
- {
- len = CertGetNameStringA(context, CERT_NAME_ATTR_TYPE, 0,
- (void *)szOID_RSA_emailAddr, str, len);
- ok(!strcmp(str, aric), "unexpected value %s\n", str);
- HeapFree(GetProcessHeap(), 0, str);
- }
- len = CertGetNameStringA(context, CERT_NAME_ATTR_TYPE, 0,
- (void *)szOID_COMMON_NAME, NULL, 0);
- ok(len == strlen(localhost) + 1, "unexpected length %ld\n", len);
- str = HeapAlloc(GetProcessHeap(), 0, len);
- if (str)
- {
- len = CertGetNameStringA(context, CERT_NAME_ATTR_TYPE, 0,
- (void *)szOID_COMMON_NAME, str, len);
- ok(!strcmp(str, localhost), "unexpected value %s\n", str);
- HeapFree(GetProcessHeap(), 0, str);
- }
-
- len = CertGetNameStringA(context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
- NULL, NULL, 0);
- ok(len == strlen(localhost) + 1, "unexpected length %ld\n", len);
- str = HeapAlloc(GetProcessHeap(), 0, len);
- if (str)
- {
- len = CertGetNameStringA(context, CERT_NAME_SIMPLE_DISPLAY_TYPE,
- 0, NULL, str, len);
- ok(!strcmp(str, localhost), "unexpected value %s\n", str);
- HeapFree(GetProcessHeap(), 0, str);
- }
-
- len = CertGetNameStringA(context, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0,
- NULL, NULL, 0);
- ok(len == strlen(localhost) + 1, "unexpected length %ld\n", len);
- str = HeapAlloc(GetProcessHeap(), 0, len);
- if (str)
- {
- len = CertGetNameStringA(context, CERT_NAME_FRIENDLY_DISPLAY_TYPE,
- 0, NULL, str, len);
- ok(!strcmp(str, localhost), "unexpected value %s\n", str);
- HeapFree(GetProcessHeap(), 0, str);
- }
-
- len = CertGetNameStringA(context, CERT_NAME_DNS_TYPE, 0, NULL, NULL,
- 0);
- ok(len == strlen(localhost) + 1, "unexpected length %ld\n", len);
- if (len > 1)
- {
- str = HeapAlloc(GetProcessHeap(), 0, len);
- if (str)
- {
- len = CertGetNameStringA(context, CERT_NAME_DNS_TYPE, 0, NULL,
- str, len);
- ok(!strcmp(str, localhost), "unexpected value %s\n", str);
- HeapFree(GetProcessHeap(), 0, str);
- }
- }
-
- CertFreeCertificateContext(context);
- }
+ ok(!!context, "CertCreateCertificateContext failed, err %lu\n", GetLastError());
+
+ /* Bad string types/types missing from the cert */
+ len = CertGetNameStringA(NULL, 0, 0, NULL, NULL, 0);
+ ok(len == 1, "expected 1, got %lu\n", len);
+ len = CertGetNameStringA(context, 0, 0, NULL, NULL, 0);
+ ok(len == 1, "expected 1, got %lu\n", len);
+ len = CertGetNameStringA(context, CERT_NAME_URL_TYPE, 0, NULL, NULL, 0);
+ ok(len == 1, "expected 1, got %lu\n", len);
+
+ len = CertGetNameStringW(NULL, 0, 0, NULL, NULL, 0);
+ ok(len == 1, "expected 1, got %lu\n", len);
+ len = CertGetNameStringW(context, 0, 0, NULL, NULL, 0);
+ ok(len == 1, "expected 1, got %lu\n", len);
+ len = CertGetNameStringW(context, CERT_NAME_URL_TYPE, 0, NULL, NULL, 0);
+ ok(len == 1, "expected 1, got %lu\n", len);
+
+ test_CertGetNameString_value(context, CERT_NAME_EMAIL_TYPE, 0, NULL, aric);
+ test_CertGetNameString_value(context, CERT_NAME_RDN_TYPE, 0, NULL, issuerStr);
+ type = 0;
+ test_CertGetNameString_value(context, CERT_NAME_RDN_TYPE, 0, &type, issuerStr);
+ type = CERT_OID_NAME_STR;
+ test_CertGetNameString_value(context, CERT_NAME_RDN_TYPE, 0, &type, subjectStr);
+ test_CertGetNameString_value(context, CERT_NAME_ATTR_TYPE, 0, NULL, aric);
+ test_CertGetNameString_value(context, CERT_NAME_ATTR_TYPE, 0, (void *)szOID_RSA_emailAddr, aric);
+ test_CertGetNameString_value(context, CERT_NAME_ATTR_TYPE, 0, (void *)szOID_COMMON_NAME, localhost);
+ test_CertGetNameString_value(context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, localhost);
+ test_CertGetNameString_value(context, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, localhost);
+ test_CertGetNameString_value(context, CERT_NAME_DNS_TYPE, 0, NULL, localhost);
+ test_CertGetNameString_value(context, CERT_NAME_DNS_TYPE, CERT_NAME_SEARCH_ALL_NAMES_FLAG, NULL, "localhost\0");
+ test_CertGetNameString_value(context, CERT_NAME_EMAIL_TYPE, CERT_NAME_SEARCH_ALL_NAMES_FLAG, NULL, "");
+ test_CertGetNameString_value(context, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_SEARCH_ALL_NAMES_FLAG, NULL, "");
+
+ CertFreeCertificateContext(context);
+
+ ok(cert_v3[CERT_V3_SAN_OID_OFFSET] == 0x55, "Incorrect CERT_V3_SAN_OID_OFFSET.\n");
+ ok(cert_v3[CERT_V3_IAN_OID_OFFSET] == 0x55, "Incorrect CERT_V3_IAN_OID_OFFSET.\n");
+ cert_v3[CERT_V3_SAN_OID_OFFSET + 2] = 7; /* legacy OID_SUBJECT_ALT_NAME */
+ cert_v3[CERT_V3_IAN_OID_OFFSET + 2] = 8; /* legacy OID_ISSUER_ALT_NAME */
+ context = CertCreateCertificateContext(X509_ASN_ENCODING, cert_v3, sizeof(cert_v3));
+ ok(!!context, "CertCreateCertificateContext failed, err %lu\n", GetLastError());
+ test_CertGetNameString_value(context, CERT_NAME_DNS_TYPE, 0, NULL, "ex1.org");
+ test_CertGetNameString_value(context, CERT_NAME_DNS_TYPE, CERT_NAME_ISSUER_FLAG, NULL, "ex3.org");
+ CertFreeCertificateContext(context);
+
+ cert_v3[CERT_V3_SAN_OID_OFFSET + 2] = 17; /* OID_SUBJECT_ALT_NAME2 */
+ cert_v3[CERT_V3_IAN_OID_OFFSET + 2] = 18; /* OID_ISSUER_ALT_NAME2 */
+ context = CertCreateCertificateContext(X509_ASN_ENCODING, cert_v3, sizeof(cert_v3));
+ ok(!!context, "CertCreateCertificateContext failed, err %lu\n", GetLastError());
+ test_CertGetNameString_value(context, CERT_NAME_DNS_TYPE, 0, NULL, "ex1.org");
+ test_CertGetNameString_value(context, CERT_NAME_DNS_TYPE, CERT_NAME_ISSUER_FLAG, NULL, "ex3.org");
+ test_CertGetNameString_value(context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, "server_cn.org");
+ test_CertGetNameString_value(context, CERT_NAME_ATTR_TYPE, 0, (void *)szOID_SUR_NAME, "");
+ test_CertGetNameString_value(context, CERT_NAME_DNS_TYPE, CERT_NAME_SEARCH_ALL_NAMES_FLAG,
+ NULL, "ex1.org\0*.ex2.org\0");
+ test_CertGetNameString_value(context, CERT_NAME_DNS_TYPE, CERT_NAME_SEARCH_ALL_NAMES_FLAG | CERT_NAME_ISSUER_FLAG,
+ NULL, "ex3.org\0*.ex4.org\0");
+ CertFreeCertificateContext(context);
}
START_TEST(str)
@@ -904,5 +987,5 @@ START_TEST(str)
test_CertNameToStrW();
test_CertStrToNameA();
test_CertStrToNameW();
- test_CertGetNameStringA();
+ test_CertGetNameString();
}
diff --git a/dlls/crypt32/unixlib.c b/dlls/crypt32/unixlib.c
index 069cb049851..9a36d12f293 100644
--- wine/dlls/crypt32/unixlib.c
+++ wine/dlls/crypt32/unixlib.c
@@ -95,21 +95,7 @@ static NTSTATUS process_attach( void *args )
setenv("GNUTLS_SYSTEM_PRIORITY_FILE", "/dev/null", 0);
}
-if (1) { /* CROSSOVER HACK - bug 10151 */
- const char *libgnutls_name_candidates[] = {SONAME_LIBGNUTLS,
- "libgnutls.so.30",
- "libgnutls.so.28",
- "libgnutls-deb0.so.28",
- "libgnutls.so.26",
- NULL};
- int i;
- for (i=0; libgnutls_name_candidates[i] && !libgnutls_handle; i++)
- libgnutls_handle = dlopen(libgnutls_name_candidates[i], RTLD_NOW);
-}
-else
- libgnutls_handle = dlopen( SONAME_LIBGNUTLS, RTLD_NOW );
-
- if (!libgnutls_handle)
+ if (!(libgnutls_handle = dlopen( SONAME_LIBGNUTLS, RTLD_NOW )))
{
ERR_(winediag)( "failed to load libgnutls, no support for pfx import/export\n" );
return STATUS_DLL_NOT_FOUND;
diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c
index 6654ef77c8c..19de1ed2d8e 100644
--- wine/dlls/cryptnet/cryptnet_main.c
+++ wine/dlls/cryptnet/cryptnet_main.c
@@ -1690,6 +1690,15 @@ static DWORD verify_cert_revocation_from_dist_points_ext(const CRYPT_DATA_BLOB *
const CRL_CONTEXT *crl;
DWORD timeout = 0;
+ if (!params || !params->pIssuerCert)
+ {
+ TRACE("no issuer certificate\n");
+ return CRYPT_E_REVOCATION_OFFLINE;
+ }
+
+ if (find_cached_revocation_status(&cert->pCertInfo->SerialNumber, time, status))
+ return status->dwError;
+
if (!CRYPT_GetUrlFromCRLDistPointsExt(value, NULL, &url_array_size, NULL, NULL))
return GetLastError();
@@ -1918,6 +1927,7 @@ static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_
HCRYPTPROV prov = 0;
HCRYPTHASH hash = 0;
HCRYPTKEY key = 0;
+ DWORD algid;
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, OCSP_BASIC_SIGNED_RESPONSE, blob->pbData, blob->cbData,
CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)) return GetLastError();
@@ -1925,7 +1935,7 @@ static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_
if ((error = check_ocsp_response_info(cert, issuer, &info->ToBeSigned, &status))) goto done;
alg = &info->SignatureInfo.SignatureAlgorithm;
- if (!alg->pszObjId || strcmp(alg->pszObjId, szOID_RSA_SHA256RSA))
+ if (!alg->pszObjId || !(algid = CertOIDToAlgId(alg->pszObjId)))
{
FIXME("unhandled signature algorithm %s\n", debugstr_a(alg->pszObjId));
error = CRYPT_E_NO_REVOCATION_CHECK;
@@ -1933,7 +1943,7 @@ static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_
}
if (!CryptAcquireContextW(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) goto done;
- if (!CryptCreateHash(prov, CALG_SHA_256, 0, 0, &hash)) goto done;
+ if (!CryptCreateHash(prov, algid, 0, 0, &hash)) goto done;
if (!CryptHashData(hash, info->ToBeSigned.pbData, info->ToBeSigned.cbData, 0)) goto done;
sig = &info->SignatureInfo.Signature;
@@ -2136,22 +2146,19 @@ static DWORD verify_cert_revocation(const CERT_CONTEXT *cert, FILETIME *pTime,
DWORD error = ERROR_SUCCESS;
PCERT_EXTENSION ext;
- if (find_cached_revocation_status(&cert->pCertInfo->SerialNumber, pTime, pRevStatus))
- return pRevStatus->dwError;
-
- if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS,
- cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
+ if ((ext = CertFindExtension(szOID_AUTHORITY_INFO_ACCESS, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
{
- error = verify_cert_revocation_from_dist_points_ext(&ext->Value, cert,
- pTime, dwFlags, pRevPara, pRevStatus);
+ error = verify_cert_revocation_from_aia_ext(&ext->Value, cert, pTime, dwFlags, pRevPara, pRevStatus);
+ TRACE("verify_cert_revocation_from_aia_ext() returned %08lx\n", error);
+ if (error == ERROR_SUCCESS || error == CRYPT_E_REVOKED) return error;
}
- else if ((ext = CertFindExtension(szOID_AUTHORITY_INFO_ACCESS,
- cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
+ if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
{
- error = verify_cert_revocation_from_aia_ext(&ext->Value, cert, pTime,
- dwFlags, pRevPara, pRevStatus);
+ error = verify_cert_revocation_from_dist_points_ext(&ext->Value, cert, pTime, dwFlags, pRevPara, pRevStatus);
+ TRACE("verify_cert_revocation_from_dist_points_ext() returned %08lx\n", error);
+ if (error == ERROR_SUCCESS || error == CRYPT_E_REVOKED) return error;
}
- else
+ if (!ext)
{
if (pRevPara && pRevPara->hCrlStore && pRevPara->pIssuerCert)
{
diff --git a/dlls/wintrust/softpub.c b/dlls/wintrust/softpub.c
index 53df5e7fe60..06b178a98b9 100644
--- wine/dlls/wintrust/softpub.c
+++ wine/dlls/wintrust/softpub.c
@@ -830,16 +830,93 @@ static DWORD WINTRUST_VerifySigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
return err;
}
+static void load_secondary_signatures(CRYPT_PROVIDER_DATA *data, HCRYPTMSG msg)
+{
+ CRYPT_PROVIDER_SIGSTATE *s = data->pSigState;
+ CRYPT_ATTRIBUTES *attrs;
+ unsigned int i, j;
+ DWORD size;
+
+ if (!CryptMsgGetParam(msg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, NULL, &size))
+ return;
+
+ if (!(attrs = data->psPfns->pfnAlloc(size)))
+ {
+ ERR("No memory.\n");
+ return;
+ }
+ if (!CryptMsgGetParam(msg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, attrs, &size))
+ goto done;
+
+ for (i = 0; i < attrs->cAttr; ++i)
+ {
+ if (strcmp(attrs->rgAttr[i].pszObjId, szOID_NESTED_SIGNATURE))
+ continue;
+
+ if (!(s->rhSecondarySigs = data->psPfns->pfnAlloc(attrs->rgAttr[i].cValue * sizeof(*s->rhSecondarySigs))))
+ {
+ ERR("No memory");
+ goto done;
+ }
+ s->cSecondarySigs = 0;
+ for (j = 0; j < attrs->rgAttr[i].cValue; ++j)
+ {
+ if (!(msg = CryptMsgOpenToDecode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL)))
+ {
+ ERR("Could not create crypt message.\n");
+ goto done;
+ }
+ if (!CryptMsgUpdate(msg, attrs->rgAttr[i].rgValue[j].pbData, attrs->rgAttr[i].rgValue[j].cbData, TRUE))
+ {
+ ERR("Could not update crypt message, err %lu.\n", GetLastError());
+ CryptMsgClose(msg);
+ goto done;
+ }
+ s->rhSecondarySigs[j] = msg;
+ ++s->cSecondarySigs;
+ }
+ break;
+ }
+done:
+ data->psPfns->pfnFree(attrs);
+}
+
HRESULT WINAPI SoftpubLoadSignature(CRYPT_PROVIDER_DATA *data)
{
- DWORD err;
+ DWORD err = ERROR_SUCCESS;
TRACE("(%p)\n", data);
if (!data->padwTrustStepErrors)
return S_FALSE;
- if (data->hMsg)
+ if (data->pSigState)
+ {
+ /* We did not initialize this, probably an unsupported usage. */
+ FIXME("pSigState %p already initialized.\n", data->pSigState);
+ }
+ if (!(data->pSigState = data->psPfns->pfnAlloc(sizeof(*data->pSigState))))
+ {
+ err = ERROR_OUTOFMEMORY;
+ }
+ else
+ {
+ data->pSigState->cbStruct = sizeof(*data->pSigState);
+ data->pSigState->fSupportMultiSig = TRUE;
+ data->pSigState->dwCryptoPolicySupport = WSS_SIGTRUST_SUPPORT | WSS_OBJTRUST_SUPPORT | WSS_CERTTRUST_SUPPORT;
+ if (data->hMsg)
+ {
+ data->pSigState->hPrimarySig = CryptMsgDuplicate(data->hMsg);
+ load_secondary_signatures(data, data->pSigState->hPrimarySig);
+ }
+ if (data->pSigSettings)
+ {
+ if (data->pSigSettings->dwFlags & WSS_GET_SECONDARY_SIG_COUNT)
+ data->pSigSettings->cSecondarySigs = data->pSigState->cSecondarySigs;
+ }
+ }
+
+ if (!err && data->hMsg)
{
DWORD signerCount, size;
@@ -859,8 +936,7 @@ HRESULT WINAPI SoftpubLoadSignature(CRYPT_PROVIDER_DATA *data)
else
err = TRUST_E_NOSIGNATURE;
}
- else
- err = ERROR_SUCCESS;
+
if (err)
data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = err;
return !err ? S_OK : S_FALSE;
@@ -1375,6 +1451,13 @@ HRESULT WINAPI SoftpubCleanup(CRYPT_PROVIDER_DATA *data)
data->psPfns->pfnFree(data->u.pPDSip->psIndirectData);
}
+ if (WVT_ISINSTRUCT(CRYPT_PROVIDER_DATA, data->cbStruct, pSigState) && data->pSigState)
+ {
+ CryptMsgClose(data->pSigState->hPrimarySig);
+ for (i = 0; i < data->pSigState->cSecondarySigs; ++i)
+ CryptMsgClose(data->pSigState->rhSecondarySigs[i]);
+ data->psPfns->pfnFree(data->pSigState);
+ }
CryptMsgClose(data->hMsg);
if (data->fOpenedFile &&
diff --git a/dlls/wintrust/tests/softpub.c b/dlls/wintrust/tests/softpub.c
index 8195e6006b1..77e15b2feb4 100644
--- wine/dlls/wintrust/tests/softpub.c
+++ wine/dlls/wintrust/tests/softpub.c
@@ -1123,6 +1123,476 @@ static const BYTE SelfSignedFile64[] =
0x9C,0x68,0x1A,0x5D,0x92,0xCD,0xD0,0x5F,0x02,0xA1,0x2C,0xD9,0x56,0x20,0x00,0x00
};
+/* Self-signed 32 bit .exe, built with mingw-gcc, stripped, signed with signtool
+ * (certificates generated with a self-signed CA).
+ *
+ * small.c:
+ * int _start()
+ * {
+ * return 0;
+ * }
+ *
+ * i686-w64-mingw32-gcc -s -nodefaultlibs -fno-PIC ./small.c -o sign_3certs.exe
+ * strip -R .idata -R .rdata -R .edata -R .eh_fram ./sign_3certs.exe
+ * signtool.exe sign /v /f cert1.pfx /fd SHA256 /t http://timestamp.digicert.com sign_3certs.exe
+ * signtool.exe sign /v /f cert2.pfx /as /fd SHA256 sign_3certs.exe
+ * signtool.exe sign /v /f cert3.pfx /as /fd SHA256 sign_3certs.exe */
+
+static const BYTE self_signed_3certs[] =
+{
+ 0x4d,0x5a,0x90,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,
+ 0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,
+ 0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,
+ 0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x45,0x00,0x00,0x4c,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0xe0,0x00,0x0e,0x03,0x0b,0x01,0x02,0x25,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x10,0x00,0x00,0x00,0x02,0x00,0x00,
+ 0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x02,0x00,0x00,
+ 0x76,0x3e,0x00,0x00,0x03,0x00,0x40,0x01,0x00,0x00,0x20,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x14,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x48,0x26,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0x74,0x65,0x78,0x74,0x00,0x00,0x00,
+ 0x1c,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0x89,0xe5,0xb8,0x00,0x00,0x00,0x00,0x5d,0xc3,0x90,0x90,0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x26,0x00,0x00,0x00,0x02,0x02,0x00,
+ 0x30,0x82,0x26,0x36,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,0x82,0x26,0x27,0x30,0x82,0x26,0x23,0x02,
+ 0x01,0x01,0x31,0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x30,0x5c,0x06,0x0a,0x2b,
+ 0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x04,0xa0,0x4e,0x30,0x4c,0x30,0x17,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,
+ 0x02,0x01,0x0f,0x30,0x09,0x03,0x01,0x00,0xa0,0x04,0xa2,0x02,0x80,0x00,0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,
+ 0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20,0xdd,0x8b,0xd7,0x29,0x3b,0xae,0x16,0xec,0xbb,0x81,0x80,0x55,0x15,0xd8,0x87,
+ 0xa5,0x3e,0xeb,0x0b,0x74,0x59,0xb6,0x56,0xf1,0x0b,0x2e,0xe1,0xb4,0x42,0x4d,0x8b,0x18,0xa0,0x82,0x16,0x0c,0x30,0x82,0x03,
+ 0x01,0x30,0x82,0x01,0xe9,0xa0,0x03,0x02,0x01,0x02,0x02,0x10,0xd1,0x73,0x97,0xaa,0xa7,0x3a,0x31,0xa2,0x44,0xc0,0x4b,0x40,
+ 0x69,0x40,0x4b,0xfa,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x30,0x12,0x31,0x10,0x30,
+ 0x0e,0x06,0x03,0x55,0x04,0x03,0x13,0x07,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d,0x32,0x32,0x30,0x39,0x33,
+ 0x30,0x31,0x37,0x31,0x39,0x33,0x32,0x5a,0x17,0x0d,0x33,0x39,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,
+ 0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x63,0x65,0x72,0x74,0x31,0x30,0x82,0x01,0x22,0x30,0x0d,0x06,
+ 0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a,0x02,0x82,0x01,
+ 0x01,0x00,0xca,0x9c,0xd9,0xd4,0x25,0xb6,0x45,0x61,0x22,0x8d,0xdf,0xe9,0x11,0x0f,0xa1,0x7e,0x45,0xc5,0x0b,0xd0,0x42,0xfc,
+ 0x1f,0x3e,0xce,0x20,0xfc,0x1b,0x37,0xe4,0x0d,0x06,0x83,0x1c,0x3a,0x71,0x0f,0x75,0xf5,0xe5,0x06,0x33,0x01,0x77,0xda,0xc5,
+ 0xe9,0x2e,0xe3,0x37,0x1e,0x51,0x6e,0x08,0xe2,0x02,0xa1,0x8c,0x11,0xc6,0xfc,0x43,0xa2,0xf5,0x7d,0x74,0x5d,0x5a,0xcc,0x85,
+ 0x27,0x38,0xd4,0xfa,0xad,0xd7,0xf9,0x77,0xe4,0xef,0xdd,0xb0,0xb1,0x3e,0xdc,0xf5,0x5d,0x7e,0x62,0xdf,0x16,0x01,0x88,0xcd,
+ 0xb0,0xfa,0x06,0x24,0xd7,0xce,0xdc,0xe2,0x27,0xab,0xc3,0x0e,0x44,0x59,0x39,0x38,0xae,0x0a,0x5a,0xbd,0x5c,0xfd,0x11,0xed,
+ 0x5e,0xb8,0xd3,0x09,0x9c,0x84,0x80,0x6f,0x38,0xdf,0xd2,0xed,0x12,0x33,0xc9,0x66,0x3e,0x77,0x95,0x40,0xca,0xbb,0x63,0xd8,
+ 0x44,0x62,0x1d,0x60,0xc1,0x0d,0x92,0x18,0x68,0x4c,0xc7,0x26,0x83,0x5b,0x38,0x45,0xda,0x8d,0xe6,0x11,0xd0,0x08,0x79,0x0c,
+ 0x13,0xb8,0xe0,0xab,0xf5,0x78,0xe2,0x45,0xfd,0x42,0x7f,0x33,0xab,0x6d,0x53,0x10,0xa3,0x02,0x3c,0xd3,0x6f,0xaf,0x50,0x2f,
+ 0x20,0xfc,0x92,0xd1,0xab,0x68,0xe8,0x00,0xa0,0x1c,0x4b,0x6f,0x02,0x5a,0xf4,0x1a,0xf1,0x06,0x79,0xa1,0x34,0x8d,0x04,0x5c,
+ 0x0d,0xfe,0x2d,0x3c,0x53,0xb6,0xae,0x80,0x7d,0x98,0xb9,0x02,0x60,0x15,0x2c,0xb2,0xe5,0xc7,0x9b,0xcf,0x78,0x53,0x37,0xd9,
+ 0xbf,0x84,0x04,0xb0,0x61,0x1c,0xea,0x24,0x7b,0xf7,0xcd,0x71,0x45,0x1a,0x00,0x22,0x21,0xa9,0x02,0x03,0x01,0x00,0x01,0xa3,
+ 0x55,0x30,0x53,0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x43,0x06,0x03,0x55,0x1d,0x01,
+ 0x04,0x3c,0x30,0x3a,0x80,0x10,0x88,0x17,0xf7,0x38,0x65,0x8b,0x78,0x78,0xf6,0x77,0xe3,0x25,0x47,0x54,0x33,0x4c,0xa1,0x14,
+ 0x30,0x12,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x03,0x13,0x07,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x82,0x10,0x2b,0x59,
+ 0xb4,0xc7,0xe2,0xce,0x08,0x97,0x46,0x48,0x32,0x17,0x0f,0x97,0xc5,0x08,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
+ 0x01,0x01,0x0b,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x9d,0x05,0x0e,0xc5,0xa0,0x5e,0x47,0x18,0x31,0x60,0xf2,0x1b,0x37,0xa4,
+ 0x89,0xf7,0x05,0x3e,0xea,0xc2,0x00,0x9f,0xcb,0xdd,0x28,0xba,0xc9,0x1f,0xfa,0x7a,0x9b,0x24,0x3d,0xb6,0x47,0x80,0xc1,0xa6,
+ 0x67,0x4d,0x48,0x3d,0xe0,0x0b,0x32,0x6a,0xa7,0x93,0xf3,0x40,0x20,0x8a,0xff,0x0f,0x9a,0xe2,0x00,0x95,0xa3,0xb3,0x57,0xc7,
+ 0x11,0xe1,0x28,0xc5,0x63,0x01,0xdf,0x4a,0xd2,0x37,0xb2,0x53,0x09,0x5c,0x4e,0x50,0x4e,0x14,0xb8,0x3e,0xb4,0x52,0xfe,0xa5,
+ 0x5d,0x14,0x3f,0x07,0x4f,0xda,0x9a,0xb9,0xbe,0x40,0xc5,0x3b,0x90,0x54,0x03,0x2e,0x79,0x0e,0x9b,0xf7,0xa9,0x74,0xeb,0x7c,
+ 0x6b,0x71,0x12,0xf2,0xce,0x9f,0xc0,0x3e,0x8a,0x09,0xa4,0x91,0x91,0x93,0x64,0x11,0xcc,0x96,0x7b,0xf9,0xac,0x65,0x6b,0xc3,
+ 0x02,0x1d,0xf8,0x0c,0x82,0x72,0x04,0x19,0x05,0x06,0x33,0x44,0x48,0x4f,0x34,0x13,0x04,0x1e,0x6c,0x11,0xc0,0x7b,0x63,0x32,
+ 0x1e,0xb3,0x4f,0x79,0xfe,0x9d,0xe6,0x3a,0xbe,0x8e,0xa7,0x5f,0x67,0x1d,0xae,0xad,0x58,0x0e,0x53,0xb8,0x15,0xe3,0x85,0x6e,
+ 0x91,0xfe,0x2d,0x81,0x84,0xb9,0xc3,0x23,0x13,0xa0,0x3f,0x72,0xb7,0xb3,0x26,0xda,0x08,0xcf,0x10,0x65,0x1e,0xd5,0x3b,0xf4,
+ 0x8f,0x18,0xe0,0xab,0xe7,0x5e,0xfc,0x62,0x9e,0x7e,0x54,0xf9,0x35,0x5a,0xf8,0xfa,0x1f,0x10,0x6f,0x63,0x3d,0xa2,0xe9,0x8a,
+ 0xd6,0x49,0xc0,0x40,0x0b,0xa1,0x5e,0x83,0xb0,0x01,0xb6,0x03,0x66,0xa5,0x8a,0xb4,0x29,0x06,0xea,0x27,0x0c,0x28,0x88,0xf3,
+ 0x38,0x5e,0x30,0x82,0x05,0x8d,0x30,0x82,0x04,0x75,0xa0,0x03,0x02,0x01,0x02,0x02,0x10,0x0e,0x9b,0x18,0x8e,0xf9,0xd0,0x2d,
+ 0xe7,0xef,0xdb,0x50,0xe2,0x08,0x40,0x18,0x5a,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0c,0x05,0x00,
+ 0x30,0x65,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0a,
+ 0x13,0x0c,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,0x6e,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0b,0x13,
+ 0x10,0x77,0x77,0x77,0x2e,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x24,0x30,0x22,0x06,0x03,0x55,
+ 0x04,0x03,0x13,0x1b,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x20,0x49,0x44,0x20,
+ 0x52,0x6f,0x6f,0x74,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d,0x32,0x32,0x30,0x38,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,
+ 0x17,0x0d,0x33,0x31,0x31,0x31,0x30,0x39,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x62,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,
+ 0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0a,0x13,0x0c,0x44,0x69,0x67,0x69,0x43,0x65,0x72,
+ 0x74,0x20,0x49,0x6e,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0b,0x13,0x10,0x77,0x77,0x77,0x2e,0x64,0x69,0x67,0x69,
+ 0x63,0x65,0x72,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x44,0x69,0x67,0x69,0x43,
+ 0x65,0x72,0x74,0x20,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x52,0x6f,0x6f,0x74,0x20,0x47,0x34,0x30,0x82,0x02,0x22,0x30,
+ 0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x02,0x0f,0x00,0x30,0x82,0x02,0x0a,0x02,
+ 0x82,0x02,0x01,0x00,0xbf,0xe6,0x90,0x73,0x68,0xde,0xbb,0xe4,0x5d,0x4a,0x3c,0x30,0x22,0x30,0x69,0x33,0xec,0xc2,0xa7,0x25,
+ 0x2e,0xc9,0x21,0x3d,0xf2,0x8a,0xd8,0x59,0xc2,0xe1,0x29,0xa7,0x3d,0x58,0xab,0x76,0x9a,0xcd,0xae,0x7b,0x1b,0x84,0x0d,0xc4,
+ 0x30,0x1f,0xf3,0x1b,0xa4,0x38,0x16,0xeb,0x56,0xc6,0x97,0x6d,0x1d,0xab,0xb2,0x79,0xf2,0xca,0x11,0xd2,0xe4,0x5f,0xd6,0x05,
+ 0x3c,0x52,0x0f,0x52,0x1f,0xc6,0x9e,0x15,0xa5,0x7e,0xbe,0x9f,0xa9,0x57,0x16,0x59,0x55,0x72,0xaf,0x68,0x93,0x70,0xc2,0xb2,
+ 0xba,0x75,0x99,0x6a,0x73,0x32,0x94,0xd1,0x10,0x44,0x10,0x2e,0xdf,0x82,0xf3,0x07,0x84,0xe6,0x74,0x3b,0x6d,0x71,0xe2,0x2d,
+ 0x0c,0x1b,0xee,0x20,0xd5,0xc9,0x20,0x1d,0x63,0x29,0x2d,0xce,0xec,0x5e,0x4e,0xc8,0x93,0xf8,0x21,0x61,0x9b,0x34,0xeb,0x05,
+ 0xc6,0x5e,0xec,0x5b,0x1a,0xbc,0xeb,0xc9,0xcf,0xcd,0xac,0x34,0x40,0x5f,0xb1,0x7a,0x66,0xee,0x77,0xc8,0x48,0xa8,0x66,0x57,
+ 0x57,0x9f,0x54,0x58,0x8e,0x0c,0x2b,0xb7,0x4f,0xa7,0x30,0xd9,0x56,0xee,0xca,0x7b,0x5d,0xe3,0xad,0xc9,0x4f,0x5e,0xe5,0x35,
+ 0xe7,0x31,0xcb,0xda,0x93,0x5e,0xdc,0x8e,0x8f,0x80,0xda,0xb6,0x91,0x98,0x40,0x90,0x79,0xc3,0x78,0xc7,0xb6,0xb1,0xc4,0xb5,
+ 0x6a,0x18,0x38,0x03,0x10,0x8d,0xd8,0xd4,0x37,0xa4,0x2e,0x05,0x7d,0x88,0xf5,0x82,0x3e,0x10,0x91,0x70,0xab,0x55,0x82,0x41,
+ 0x32,0xd7,0xdb,0x04,0x73,0x2a,0x6e,0x91,0x01,0x7c,0x21,0x4c,0xd4,0xbc,0xae,0x1b,0x03,0x75,0x5d,0x78,0x66,0xd9,0x3a,0x31,
+ 0x44,0x9a,0x33,0x40,0xbf,0x08,0xd7,0x5a,0x49,0xa4,0xc2,0xe6,0xa9,0xa0,0x67,0xdd,0xa4,0x27,0xbc,0xa1,0x4f,0x39,0xb5,0x11,
+ 0x58,0x17,0xf7,0x24,0x5c,0x46,0x8f,0x64,0xf7,0xc1,0x69,0x88,0x76,0x98,0x76,0x3d,0x59,0x5d,0x42,0x76,0x87,0x89,0x97,0x69,
+ 0x7a,0x48,0xf0,0xe0,0xa2,0x12,0x1b,0x66,0x9a,0x74,0xca,0xde,0x4b,0x1e,0xe7,0x0e,0x63,0xae,0xe6,0xd4,0xef,0x92,0x92,0x3a,
+ 0x9e,0x3d,0xdc,0x00,0xe4,0x45,0x25,0x89,0xb6,0x9a,0x44,0x19,0x2b,0x7e,0xc0,0x94,0xb4,0xd2,0x61,0x6d,0xeb,0x33,0xd9,0xc5,
+ 0xdf,0x4b,0x04,0x00,0xcc,0x7d,0x1c,0x95,0xc3,0x8f,0xf7,0x21,0xb2,0xb2,0x11,0xb7,0xbb,0x7f,0xf2,0xd5,0x8c,0x70,0x2c,0x41,
+ 0x60,0xaa,0xb1,0x63,0x18,0x44,0x95,0x1a,0x76,0x62,0x7e,0xf6,0x80,0xb0,0xfb,0xe8,0x64,0xa6,0x33,0xd1,0x89,0x07,0xe1,0xbd,
+ 0xb7,0xe6,0x43,0xa4,0x18,0xb8,0xa6,0x77,0x01,0xe1,0x0f,0x94,0x0c,0x21,0x1d,0xb2,0x54,0x29,0x25,0x89,0x6c,0xe5,0x0e,0x52,
+ 0x51,0x47,0x74,0xbe,0x26,0xac,0xb6,0x41,0x75,0xde,0x7a,0xac,0x5f,0x8d,0x3f,0xc9,0xbc,0xd3,0x41,0x11,0x12,0x5b,0xe5,0x10,
+ 0x50,0xeb,0x31,0xc5,0xca,0x72,0x16,0x22,0x09,0xdf,0x7c,0x4c,0x75,0x3f,0x63,0xec,0x21,0x5f,0xc4,0x20,0x51,0x6b,0x6f,0xb1,
+ 0xab,0x86,0x8b,0x4f,0xc2,0xd6,0x45,0x5f,0x9d,0x20,0xfc,0xa1,0x1e,0xc5,0xc0,0x8f,0xa2,0xb1,0x7e,0x0a,0x26,0x99,0xf5,0xe4,
+ 0x69,0x2f,0x98,0x1d,0x2d,0xf5,0xd9,0xa9,0xb2,0x1d,0xe5,0x1b,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0x3a,0x30,0x82,0x01,
+ 0x36,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x1d,0x06,0x03,0x55,0x1d,
+ 0x0e,0x04,0x16,0x04,0x14,0xec,0xd7,0xe3,0x82,0xd2,0x71,0x5d,0x64,0x4c,0xdf,0x2e,0x67,0x3f,0xe7,0xba,0x98,0xae,0x1c,0x0f,
+ 0x4f,0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x45,0xeb,0xa2,0xaf,0xf4,0x92,0xcb,0x82,0x31,0x2d,
+ 0x51,0x8b,0xa7,0xa7,0x21,0x9d,0xf3,0x6d,0xc8,0x0f,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,
+ 0x01,0x86,0x30,0x79,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x6d,0x30,0x6b,0x30,0x24,0x06,0x08,0x2b,0x06,
+ 0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,0x63,0x73,0x70,0x2e,0x64,0x69,0x67,0x69,
+ 0x63,0x65,0x72,0x74,0x2e,0x63,0x6f,0x6d,0x30,0x43,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x37,0x68,0x74,
+ 0x74,0x70,0x3a,0x2f,0x2f,0x63,0x61,0x63,0x65,0x72,0x74,0x73,0x2e,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2e,0x63,0x6f,
+ 0x6d,0x2f,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x49,0x44,0x52,0x6f,0x6f,0x74,0x43,
+ 0x41,0x2e,0x63,0x72,0x74,0x30,0x45,0x06,0x03,0x55,0x1d,0x1f,0x04,0x3e,0x30,0x3c,0x30,0x3a,0xa0,0x38,0xa0,0x36,0x86,0x34,
+ 0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x33,0x2e,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2e,0x63,0x6f,0x6d,
+ 0x2f,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x49,0x44,0x52,0x6f,0x6f,0x74,0x43,0x41,
+ 0x2e,0x63,0x72,0x6c,0x30,0x11,0x06,0x03,0x55,0x1d,0x20,0x04,0x0a,0x30,0x08,0x30,0x06,0x06,0x04,0x55,0x1d,0x20,0x00,0x30,
+ 0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0c,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x70,0xa0,0xbf,0x43,0x5c,
+ 0x55,0xe7,0x38,0x5f,0xa0,0xa3,0x74,0x1b,0x3d,0xb6,0x16,0xd7,0xf7,0xbf,0x57,0x07,0xbd,0x9a,0xac,0xa1,0x87,0x2c,0xec,0x85,
+ 0x5e,0xa9,0x1a,0xbb,0x22,0xf8,0x87,0x1a,0x69,0x54,0x22,0xed,0xa4,0x88,0x77,0x6d,0xbd,0x1a,0x14,0xf4,0x13,0x4a,0x7a,0x2f,
+ 0x2d,0xb7,0x38,0xef,0xf4,0xff,0x80,0xb9,0xf8,0xa1,0xf7,0xf2,0x72,0xde,0x24,0xbc,0x52,0x03,0xc8,0x4e,0xd0,0x2a,0xde,0xfa,
+ 0x2d,0x56,0xcf,0xf9,0xf4,0xf7,0xac,0x30,0x7a,0x9a,0x8b,0xb2,0x5e,0xd4,0xcf,0xd1,0x43,0x44,0x9b,0x43,0x21,0xeb,0x96,0x72,
+ 0xa1,0x48,0xb4,0x99,0xcb,0x9d,0x4f,0xa7,0x06,0x03,0x13,0x77,0x27,0x44,0xd4,0xe7,0x7f,0xe8,0x59,0xa8,0xf0,0xbf,0x2f,0x0b,
+ 0xa6,0xe9,0xf2,0x34,0x3c,0xec,0xf7,0x03,0xc7,0x87,0xa8,0xd2,0x4c,0x40,0x19,0x35,0x46,0x6a,0x69,0x54,0xb0,0xb8,0xa1,0x56,
+ 0x8e,0xec,0xa4,0xd5,0x3d,0xe8,0xb1,0xdc,0xfd,0x1c,0xd8,0xf4,0x77,0x5a,0x5c,0x54,0x8c,0x6f,0xef,0xa1,0x50,0x3d,0xfc,0x76,
+ 0x09,0x68,0x84,0x9f,0x6f,0xca,0xdb,0x20,0x8d,0x35,0x60,0x1c,0x02,0x03,0xcb,0x20,0xb0,0xac,0x58,0xa0,0x0e,0x40,0x63,0xc5,
+ 0x98,0x22,0xc1,0xb2,0x59,0xf5,0x55,0x6b,0xcf,0x27,0xab,0x6c,0x76,0xce,0x6f,0x23,0x2d,0xf4,0x7e,0x71,0x6a,0x23,0x6b,0x22,
+ 0xff,0x12,0xb8,0x54,0x2d,0x27,0x7e,0xd8,0x3a,0xd9,0xf0,0xb6,0x87,0x96,0xfd,0x5b,0xd1,0x5c,0xac,0x18,0xc3,0x4d,0x9f,0x73,
+ 0xb7,0x01,0xa9,0x9f,0x57,0xaa,0x5e,0x28,0xe2,0xb9,0x94,0x30,0x82,0x06,0xae,0x30,0x82,0x04,0x96,0xa0,0x03,0x02,0x01,0x02,
+ 0x02,0x10,0x07,0x36,0x37,0xb7,0x24,0x54,0x7c,0xd8,0x47,0xac,0xfd,0x28,0x66,0x2a,0x5e,0x5b,0x30,0x0d,0x06,0x09,0x2a,0x86,
+ 0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x30,0x62,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,
+ 0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0a,0x13,0x0c,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,0x6e,0x63,0x31,
+ 0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0b,0x13,0x10,0x77,0x77,0x77,0x2e,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2e,0x63,
+ 0x6f,0x6d,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x54,0x72,
+ 0x75,0x73,0x74,0x65,0x64,0x20,0x52,0x6f,0x6f,0x74,0x20,0x47,0x34,0x30,0x1e,0x17,0x0d,0x32,0x32,0x30,0x33,0x32,0x33,0x30,
+ 0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x33,0x37,0x30,0x33,0x32,0x32,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x63,0x31,
+ 0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x44,
+ 0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x3b,0x30,0x39,0x06,0x03,0x55,0x04,0x03,0x13,0x32,
+ 0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x47,0x34,0x20,0x52,0x53,0x41,0x34,
+ 0x30,0x39,0x36,0x20,0x53,0x48,0x41,0x32,0x35,0x36,0x20,0x54,0x69,0x6d,0x65,0x53,0x74,0x61,0x6d,0x70,0x69,0x6e,0x67,0x20,
+ 0x43,0x41,0x30,0x82,0x02,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x02,
+ 0x0f,0x00,0x30,0x82,0x02,0x0a,0x02,0x82,0x02,0x01,0x00,0xc6,0x86,0x35,0x06,0x49,0xb3,0xc1,0x3d,0x72,0x49,0x51,0x55,0xc7,
+ 0x25,0x03,0xc4,0xf2,0x91,0x37,0xa9,0x97,0x51,0xa1,0xd6,0xd2,0x83,0xd1,0x9e,0x4c,0xa2,0x6d,0xa0,0xb0,0xcc,0x83,0xf9,0x5a,
+ 0xf6,0x11,0xa1,0x44,0x15,0x42,0x5f,0xa4,0x88,0xf3,0x68,0xfa,0x7d,0xf3,0x9c,0x89,0x0b,0x7f,0x9d,0x1f,0x9e,0x0f,0x33,0x1f,
+ 0x50,0x13,0x0b,0x26,0x73,0x96,0x6d,0xf8,0x57,0xa8,0x02,0x7d,0xfd,0x43,0xb4,0x84,0xda,0x11,0xf1,0x73,0xb1,0xb3,0xee,0x2b,
+ 0x80,0x84,0x8a,0x22,0x18,0xdf,0xeb,0xda,0x3d,0xc4,0x17,0x7f,0xab,0x19,0x2b,0x3e,0x42,0xdc,0x67,0x8e,0xea,0x51,0x3d,0xf0,
+ 0xd6,0x56,0xd4,0xe7,0x28,0x2d,0xeb,0xd3,0xb1,0xb5,0x75,0xe7,0x1f,0x06,0x65,0x8d,0x94,0x29,0xd3,0xd9,0xec,0x69,0xdf,0xd9,
+ 0x90,0x87,0x46,0x00,0x7b,0xdb,0x44,0x41,0x89,0xdc,0x7c,0x6a,0x57,0x7a,0xf0,0x37,0x79,0x9f,0x5d,0xac,0xcb,0xe8,0x84,0x64,
+ 0xb4,0x52,0xf2,0x76,0x47,0xf7,0x61,0x83,0x19,0xdd,0x5f,0xb4,0x54,0x0b,0x21,0x68,0x6e,0x37,0x21,0xbb,0x40,0xac,0x5f,0xb2,
+ 0xde,0x4a,0x7d,0xce,0xf5,0x39,0x12,0x67,0xef,0x0e,0xa5,0x63,0x6c,0xe4,0xa6,0xc5,0x1d,0xcd,0x36,0x0d,0x5c,0xd5,0xe6,0x1b,
+ 0xa8,0xc1,0x64,0x74,0x40,0xa7,0xc0,0x72,0xc5,0xba,0x4e,0x1f,0xb1,0xb5,0x58,0x4d,0x79,0xfe,0xd7,0x8f,0x73,0x93,0xac,0x2c,
+ 0x39,0xe2,0xa5,0x48,0xd6,0xf0,0xb0,0x31,0x13,0xa9,0x57,0x29,0x96,0x27,0x2e,0xf5,0x87,0xa6,0x8f,0x4e,0x76,0x15,0x55,0x26,
+ 0x70,0x98,0x26,0x7f,0xa0,0x1a,0x47,0x20,0x43,0xe3,0x43,0x63,0x80,0x7b,0x75,0x6e,0x27,0x25,0x90,0x98,0x3a,0x38,0x11,0xb3,
+ 0xf6,0xf6,0x9e,0xe6,0x3b,0x5b,0xec,0x81,0xde,0x22,0x14,0xd9,0x82,0x2a,0xc7,0x92,0xbf,0xa0,0xde,0xe3,0x3e,0xa2,0x73,0xfa,
+ 0xe7,0x1f,0x5a,0x6c,0x94,0xf2,0x52,0x95,0x11,0x2b,0x58,0x74,0x40,0x28,0xab,0x73,0x43,0xce,0xdf,0x4a,0xa1,0x1c,0x6b,0x38,
+ 0xc5,0x29,0xf3,0xca,0xaa,0x96,0x73,0x42,0x68,0x9f,0xb6,0x46,0xb3,0x9d,0x3a,0xa3,0xd5,0x03,0xe0,0xbf,0xf0,0xa2,0x3c,0xca,
+ 0x42,0xdc,0x18,0x48,0x7f,0x14,0x34,0xcf,0xd2,0x4c,0xab,0xef,0x9b,0x3d,0xfe,0x0e,0xb8,0x64,0x2a,0xfa,0x75,0x28,0x24,0x41,
+ 0xed,0x42,0xbf,0x05,0x9c,0x66,0x49,0x52,0x50,0xf4,0x51,0xf3,0x36,0x49,0x4d,0x8b,0x20,0xd2,0x2c,0x57,0x35,0x79,0x2b,0xa8,
+ 0xf3,0x45,0x60,0xbc,0x23,0x8d,0x58,0xf7,0xdc,0x61,0xde,0x93,0xfe,0x39,0xc0,0xf9,0xb2,0x30,0xa5,0x4c,0xd7,0xe9,0x98,0x4a,
+ 0x58,0x3e,0xd3,0x03,0x88,0xfe,0xb3,0x8f,0xd3,0x5e,0x4b,0x76,0x12,0x51,0x93,0xc9,0x8c,0x0c,0x3b,0x5b,0x8a,0x22,0xa8,0xc1,
+ 0x26,0x08,0xf9,0x14,0x10,0x12,0x03,0x7d,0x5f,0x23,0xbb,0x64,0xe3,0x63,0xe0,0xa6,0xe1,0x3e,0xf6,0xc2,0x74,0xb2,0x3f,0x1e,
+ 0x09,0x76,0xec,0xab,0x5d,0x46,0x75,0xe2,0x60,0xa3,0x58,0x09,0x01,0x28,0x00,0x0e,0x84,0x54,0xee,0xce,0xe9,0x5d,0xc8,0x5e,
+ 0x30,0x12,0xbd,0x46,0x9e,0xb5,0xd3,0x76,0xb9,0xd2,0x0e,0x6b,0x99,0x0c,0xd2,0x33,0xb4,0xcd,0xb1,0x02,0x03,0x01,0x00,0x01,
+ 0xa3,0x82,0x01,0x5d,0x30,0x82,0x01,0x59,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,
+ 0xff,0x02,0x01,0x00,0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,0x04,0x16,0x04,0x14,0xba,0x16,0xd9,0x6d,0x4d,0x85,0x2f,0x73,0x29,
+ 0x76,0x9a,0x2f,0x75,0x8c,0x6a,0x20,0x8f,0x9e,0xc8,0x6f,0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,
+ 0xec,0xd7,0xe3,0x82,0xd2,0x71,0x5d,0x64,0x4c,0xdf,0x2e,0x67,0x3f,0xe7,0xba,0x98,0xae,0x1c,0x0f,0x4f,0x30,0x0e,0x06,0x03,
+ 0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x13,0x06,0x03,0x55,0x1d,0x25,0x04,0x0c,0x30,0x0a,0x06,
+ 0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x08,0x30,0x77,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x6b,0x30,
+ 0x69,0x30,0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,0x63,
+ 0x73,0x70,0x2e,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2e,0x63,0x6f,0x6d,0x30,0x41,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,
+ 0x07,0x30,0x02,0x86,0x35,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,0x61,0x63,0x65,0x72,0x74,0x73,0x2e,0x64,0x69,0x67,0x69,
+ 0x63,0x65,0x72,0x74,0x2e,0x63,0x6f,0x6d,0x2f,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x54,0x72,0x75,0x73,0x74,0x65,0x64,
+ 0x52,0x6f,0x6f,0x74,0x47,0x34,0x2e,0x63,0x72,0x74,0x30,0x43,0x06,0x03,0x55,0x1d,0x1f,0x04,0x3c,0x30,0x3a,0x30,0x38,0xa0,
+ 0x36,0xa0,0x34,0x86,0x32,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x33,0x2e,0x64,0x69,0x67,0x69,0x63,0x65,0x72,
+ 0x74,0x2e,0x63,0x6f,0x6d,0x2f,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x52,0x6f,0x6f,
+ 0x74,0x47,0x34,0x2e,0x63,0x72,0x6c,0x30,0x20,0x06,0x03,0x55,0x1d,0x20,0x04,0x19,0x30,0x17,0x30,0x08,0x06,0x06,0x67,0x81,
+ 0x0c,0x01,0x04,0x02,0x30,0x0b,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xfd,0x6c,0x07,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,
+ 0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x7d,0x59,0x8e,0xc0,0x93,0xb6,0x6f,0x98,0xa9,0x44,0x22,
+ 0x01,0x7e,0x66,0xd6,0xd8,0x21,0x42,0xe1,0xb0,0x18,0x2e,0x10,0x4d,0x13,0xcf,0x30,0x53,0xce,0xbf,0x18,0xfb,0xc7,0x50,0x5d,
+ 0xe2,0x4b,0x29,0xfb,0x70,0x8a,0x0d,0xaa,0x29,0x69,0xfc,0x69,0xc1,0xcf,0x1d,0x07,0xe9,0x3e,0x60,0xc8,0xd8,0x0b,0xe5,0x5c,
+ 0x5b,0xd7,0x6d,0x87,0xfa,0x84,0x20,0x25,0x34,0x31,0x67,0xcd,0xb6,0x12,0x96,0x6f,0xc4,0x50,0x4c,0x62,0x1d,0x0c,0x08,0x82,
+ 0xa8,0x16,0xbd,0xa9,0x56,0xcf,0x15,0x73,0x8d,0x01,0x22,0x25,0xce,0x95,0x69,0x3f,0x47,0x77,0xfb,0x72,0x74,0x14,0xd7,0xff,
+ 0xab,0x4f,0x8a,0x2c,0x7a,0xab,0x85,0xcd,0x43,0x5f,0xed,0x60,0xb6,0xaa,0x4f,0x91,0x66,0x9e,0x2c,0x9e,0xe0,0x8a,0xac,0xe5,
+ 0xfd,0x8c,0xbc,0x64,0x26,0x87,0x6c,0x92,0xbd,0x9d,0x7c,0xd0,0x70,0x0a,0x7c,0xef,0xa8,0xbc,0x75,0x4f,0xba,0x5a,0xf7,0xa9,
+ 0x10,0xb2,0x5d,0xe9,0xff,0x28,0x54,0x89,0xf0,0xd5,0x8a,0x71,0x76,0x65,0xda,0xcc,0xf0,0x72,0xa3,0x23,0xfa,0xc0,0x27,0x82,
+ 0x44,0xae,0x99,0x27,0x1b,0xab,0x24,0x1e,0x26,0xc1,0xb7,0xde,0x2a,0xeb,0xf6,0x9e,0xb1,0x79,0x99,0x81,0xa3,0x56,0x86,0xab,
+ 0x0a,0x45,0xc9,0xdf,0xc4,0x8d,0xa0,0xe7,0x98,0xfb,0xfb,0xa6,0x9d,0x72,0xaf,0xc4,0xc7,0xc1,0xc1,0x6a,0x71,0xd9,0xc6,0x13,
+ 0x80,0x09,0xc4,0xb6,0x9f,0xcd,0x87,0x87,0x24,0xbb,0x4f,0xa3,0x49,0xb9,0x77,0x66,0x91,0xf1,0x72,0x9c,0xe9,0x4b,0x02,0x52,
+ 0xa7,0x37,0x7e,0x93,0x53,0xac,0x3b,0x1d,0x08,0x49,0x0f,0x94,0xcd,0x39,0x7a,0xdd,0xff,0x25,0x63,0x99,0x27,0x2c,0x3d,0x3f,
+ 0x6b,0xa7,0xf1,0x66,0xc3,0x41,0xcd,0x4f,0xb6,0x40,0x9b,0x21,0x21,0x40,0xd0,0xb7,0x13,0x24,0xcd,0xdc,0x1d,0x78,0x3a,0xe4,
+ 0x9e,0xad,0xe5,0x34,0x71,0x92,0xd7,0x26,0x6b,0xe4,0x38,0x73,0xab,0xa6,0x01,0x4f,0xbd,0x3f,0x3b,0x78,0xad,0x4c,0xad,0xfb,
+ 0xc4,0x95,0x7b,0xed,0x0a,0x5f,0x33,0x39,0x87,0x41,0x78,0x7a,0x38,0xe9,0x9c,0xe1,0xdd,0x23,0xfd,0x1d,0x28,0xd3,0xc7,0xf9,
+ 0xe8,0xf1,0x98,0x5f,0xfb,0x2b,0xd8,0x7e,0xf2,0x46,0x9d,0x75,0x2c,0x1e,0x27,0x2c,0x26,0xdb,0x6f,0x15,0x7b,0x1e,0x19,0x8b,
+ 0x36,0xb8,0x93,0xd4,0xe6,0xf2,0x17,0x99,0x59,0xca,0x70,0xf0,0x37,0xbf,0x98,0x00,0xdf,0x20,0x16,0x4f,0x27,0xfb,0x60,0x67,
+ 0x16,0xa1,0x66,0xba,0xdd,0x55,0xc0,0x3a,0x29,0x86,0xb0,0x98,0xa0,0x2b,0xed,0x95,0x41,0xb7,0x3a,0xd5,0x15,0x98,0x31,0xb4,
+ 0x62,0x09,0x0f,0x0a,0xbd,0x81,0xd9,0x13,0xfe,0xbf,0xa4,0xd1,0xf3,0x57,0xd9,0xbc,0x04,0xfa,0x82,0xde,0x32,0xdf,0x04,0x89,
+ 0xf0,0x00,0xcd,0x5d,0xc2,0xf9,0xd0,0x23,0x7f,0x00,0x0b,0xe4,0x76,0x02,0x26,0xd9,0xf0,0x65,0x76,0x42,0xa6,0x29,0x87,0x09,
+ 0x47,0x2b,0xe6,0x7f,0x1a,0xa4,0x85,0x0f,0xfc,0x98,0x96,0xf6,0x55,0x54,0x2b,0x1f,0x80,0xfa,0xc0,0xf2,0x0e,0x2b,0xe5,0xd6,
+ 0xfb,0xa9,0x2f,0x44,0x15,0x4a,0xe7,0x13,0x0e,0x1d,0xdb,0x37,0x38,0x1a,0xa1,0x2b,0xf6,0xed,0xd6,0x7c,0xfc,0x30,0x82,0x06,
+ 0xc0,0x30,0x82,0x04,0xa8,0xa0,0x03,0x02,0x01,0x02,0x02,0x10,0x0c,0x4d,0x69,0x72,0x4b,0x94,0xfa,0x3c,0x2a,0x4a,0x3d,0x29,
+ 0x07,0x80,0x3d,0x5a,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x30,0x63,0x31,0x0b,0x30,
+ 0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x44,0x69,0x67,
+ 0x69,0x43,0x65,0x72,0x74,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x3b,0x30,0x39,0x06,0x03,0x55,0x04,0x03,0x13,0x32,0x44,0x69,
+ 0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x47,0x34,0x20,0x52,0x53,0x41,0x34,0x30,0x39,
+ 0x36,0x20,0x53,0x48,0x41,0x32,0x35,0x36,0x20,0x54,0x69,0x6d,0x65,0x53,0x74,0x61,0x6d,0x70,0x69,0x6e,0x67,0x20,0x43,0x41,
+ 0x30,0x1e,0x17,0x0d,0x32,0x32,0x30,0x39,0x32,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x33,0x33,0x31,0x31,0x32,
+ 0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x46,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,
+ 0x11,0x30,0x0f,0x06,0x03,0x55,0x04,0x0a,0x13,0x08,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x31,0x24,0x30,0x22,0x06,0x03,
+ 0x55,0x04,0x03,0x13,0x1b,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x54,0x69,0x6d,0x65,0x73,0x74,0x61,0x6d,0x70,0x20,
+ 0x32,0x30,0x32,0x32,0x20,0x2d,0x20,0x32,0x30,0x82,0x02,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,
+ 0x01,0x05,0x00,0x03,0x82,0x02,0x0f,0x00,0x30,0x82,0x02,0x0a,0x02,0x82,0x02,0x01,0x00,0xcf,0xec,0xa5,0x26,0x3a,0xc6,0xa9,
+ 0xf2,0x6b,0xbb,0x8d,0xc1,0x0d,0x9a,0xdb,0xa1,0xe8,0x14,0x85,0x74,0x33,0x1a,0x26,0xac,0xd0,0x1c,0x55,0x1e,0x1e,0x36,0x6d,
+ 0xbc,0x92,0x55,0x0c,0x61,0xf4,0x9d,0x09,0x77,0x3d,0x15,0x96,0x08,0x2f,0x6b,0x64,0xa4,0xfd,0x06,0x83,0x16,0xd7,0x91,0x92,
+ 0x38,0x1c,0x31,0x02,0x96,0xfb,0x72,0xb1,0x97,0x3a,0x55,0xaf,0x33,0xec,0x61,0x8a,0xe9,0xa6,0x28,0xdb,0x90,0x63,0x5c,0xbd,
+ 0x89,0x53,0xe0,0x3a,0x2d,0x8c,0x87,0x42,0xae,0x26,0xa4,0xe4,0xbb,0x78,0x78,0xb9,0x7a,0x16,0xe1,0x56,0xc6,0xc0,0xba,0x64,
+ 0x53,0xbb,0x2a,0x16,0xe7,0x50,0x48,0xbb,0x88,0x69,0x0c,0x88,0xc6,0xf1,0xbe,0xe0,0x2f,0x7d,0x3b,0xb1,0xca,0x53,0x8d,0x40,
+ 0x83,0x1e,0xe7,0xcb,0x72,0x49,0x28,0x1e,0x4c,0x80,0x1e,0x85,0x56,0xe7,0x85,0xed,0xf2,0x61,0xbc,0xaa,0x3a,0x07,0x7d,0xf6,
+ 0xab,0x6e,0xe5,0x66,0xdd,0xe2,0x5c,0xf5,0x2f,0xed,0x8d,0xd4,0x4d,0x95,0x84,0x68,0xe3,0x80,0xcb,0x6a,0x79,0xd1,0xd2,0x10,
+ 0x91,0x46,0x29,0xeb,0x3e,0x26,0xf2,0xb4,0x8c,0xcd,0x4c,0xb9,0x66,0xc8,0xbb,0xaa,0x50,0x38,0x0d,0xe5,0x8c,0x94,0x5d,0x19,
+ 0x5a,0xbf,0xf5,0x7b,0x40,0x6e,0x6f,0x16,0xa8,0x9a,0x9c,0x95,0x47,0x86,0x85,0x79,0x3e,0x0c,0x5e,0x66,0x8c,0x1a,0x0a,0x24,
+ 0xbe,0x9c,0xaa,0xd2,0x9c,0xb6,0xf7,0x4f,0x6e,0x78,0xc4,0x28,0x3f,0xa3,0x1c,0x0f,0x50,0x06,0x37,0xba,0x08,0xd9,0x35,0xa6,
+ 0xb5,0x1e,0xda,0x78,0x58,0x1d,0x39,0xe8,0xf8,0x4c,0x91,0x10,0x96,0x7e,0x4d,0xe1,0xdd,0xc2,0xad,0xa5,0x7e,0xf8,0x2d,0x1b,
+ 0x1f,0xec,0x2b,0x46,0x18,0xa3,0x19,0xf6,0x39,0xf7,0xf5,0xc1,0x4f,0x71,0x2e,0x89,0x03,0x11,0xa2,0x4b,0xbb,0x98,0xbf,0xfa,
+ 0x4f,0xe4,0x7b,0x36,0xef,0x06,0x44,0xe4,0x55,0xff,0x36,0xea,0xe5,0x7c,0x31,0xe7,0xf3,0xc2,0x52,0xc4,0xe6,0x16,0x7b,0x5a,
+ 0x7e,0xa5,0x25,0x73,0xdb,0xc0,0x6a,0x99,0x21,0x2d,0x63,0xe5,0x59,0xf5,0x4d,0x2f,0x90,0x1f,0x27,0xb7,0xd2,0xab,0x14,0xe5,
+ 0x38,0x66,0x87,0x51,0x08,0x6b,0xfb,0x53,0x43,0x39,0xd0,0x64,0xfa,0x56,0xcf,0xe0,0xf4,0x0a,0xe6,0x14,0x6d,0x64,0x78,0xbb,
+ 0x98,0xfd,0x94,0xc3,0x73,0x21,0xf3,0x2f,0xc2,0x2e,0x20,0xd7,0x81,0xac,0xd3,0xf1,0x07,0xd4,0xe1,0xbd,0xd9,0x5d,0x4b,0x6e,
+ 0x31,0x94,0x29,0x8b,0xe6,0x41,0xa4,0x65,0x94,0xc0,0x58,0xe5,0xe5,0x2e,0x29,0x90,0xa6,0xb7,0x61,0x64,0xfa,0xd9,0x20,0x6c,
+ 0x18,0x51,0x60,0xba,0xa6,0x81,0x0f,0x09,0x25,0x53,0xf1,0xbf,0x3b,0xe9,0xab,0x07,0x0e,0x6a,0x07,0x39,0x62,0x19,0xc9,0xd6,
+ 0x85,0x7f,0x13,0xd9,0x8d,0x79,0xcf,0x62,0xc5,0xec,0xe1,0x7b,0xb9,0xcc,0x67,0x13,0x07,0x9a,0xc1,0x78,0xed,0xc6,0x88,0xc8,
+ 0xb0,0x6e,0x32,0x79,0xc7,0x0b,0x59,0x83,0x8d,0xc6,0xee,0xf5,0x2c,0x7c,0x7b,0x8e,0xcb,0x64,0x89,0xf1,0xb1,0xc4,0xb8,0xe7,
+ 0x53,0x5e,0x5f,0x55,0xd2,0x7d,0x19,0x29,0x59,0x03,0x4e,0xfa,0x5d,0xea,0x45,0x73,0x1c,0x84,0x7e,0xd7,0xce,0xe2,0xd4,0x3a,
+ 0x77,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0x8b,0x30,0x82,0x01,0x87,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,
+ 0x04,0x04,0x03,0x02,0x07,0x80,0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x16,0x06,0x03,
+ 0x55,0x1d,0x25,0x01,0x01,0xff,0x04,0x0c,0x30,0x0a,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x08,0x30,0x20,0x06,0x03,
+ 0x55,0x1d,0x20,0x04,0x19,0x30,0x17,0x30,0x08,0x06,0x06,0x67,0x81,0x0c,0x01,0x04,0x02,0x30,0x0b,0x06,0x09,0x60,0x86,0x48,
+ 0x01,0x86,0xfd,0x6c,0x07,0x01,0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xba,0x16,0xd9,0x6d,0x4d,
+ 0x85,0x2f,0x73,0x29,0x76,0x9a,0x2f,0x75,0x8c,0x6a,0x20,0x8f,0x9e,0xc8,0x6f,0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,0x04,0x16,
+ 0x04,0x14,0x62,0x8a,0xde,0xd0,0x61,0xfc,0x8f,0x31,0x14,0xed,0x97,0x0b,0xcd,0x3d,0x2a,0x94,0x14,0xdf,0x52,0x9c,0x30,0x5a,
+ 0x06,0x03,0x55,0x1d,0x1f,0x04,0x53,0x30,0x51,0x30,0x4f,0xa0,0x4d,0xa0,0x4b,0x86,0x49,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
+ 0x63,0x72,0x6c,0x33,0x2e,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2e,0x63,0x6f,0x6d,0x2f,0x44,0x69,0x67,0x69,0x43,0x65,
+ 0x72,0x74,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x47,0x34,0x52,0x53,0x41,0x34,0x30,0x39,0x36,0x53,0x48,0x41,0x32,0x35,0x36,
+ 0x54,0x69,0x6d,0x65,0x53,0x74,0x61,0x6d,0x70,0x69,0x6e,0x67,0x43,0x41,0x2e,0x63,0x72,0x6c,0x30,0x81,0x90,0x06,0x08,0x2b,
+ 0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x81,0x83,0x30,0x81,0x80,0x30,0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,
+ 0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,0x63,0x73,0x70,0x2e,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2e,
+ 0x63,0x6f,0x6d,0x30,0x58,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x4c,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
+ 0x63,0x61,0x63,0x65,0x72,0x74,0x73,0x2e,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2e,0x63,0x6f,0x6d,0x2f,0x44,0x69,0x67,
+ 0x69,0x43,0x65,0x72,0x74,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x47,0x34,0x52,0x53,0x41,0x34,0x30,0x39,0x36,0x53,0x48,0x41,
+ 0x32,0x35,0x36,0x54,0x69,0x6d,0x65,0x53,0x74,0x61,0x6d,0x70,0x69,0x6e,0x67,0x43,0x41,0x2e,0x63,0x72,0x74,0x30,0x0d,0x06,
+ 0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x55,0xaa,0x2a,0x1a,0xf3,0x46,0xf3,
+ 0x78,0x57,0x37,0x30,0xfc,0x75,0xe3,0x4f,0xd6,0x85,0x23,0xf1,0xfc,0xf9,0x95,0x39,0x9b,0x25,0xe6,0xf7,0x72,0x8a,0x98,0xc3,
+ 0x77,0xd4,0x64,0xfc,0x15,0xfb,0x36,0xc2,0x49,0x51,0x2c,0x78,0x88,0x63,0x55,0x09,0x46,0x39,0x00,0xfc,0x69,0xd4,0xca,0x9b,
+ 0x29,0xfb,0xa3,0x3f,0xc0,0xc9,0x00,0x9b,0x13,0x1d,0xb0,0x98,0x89,0xdc,0x78,0xf2,0xcd,0x7c,0x85,0xcd,0x53,0x9d,0xaf,0x62,
+ 0xe2,0x61,0x66,0xa3,0x14,0x2a,0x45,0x87,0x4a,0x98,0x42,0x2b,0x50,0xfc,0x1b,0xb5,0x9e,0x08,0x30,0x09,0xfa,0xe4,0x2d,0xd7,
+ 0x09,0x89,0x79,0xf9,0x09,0xe6,0x88,0xce,0x7d,0x1b,0xb8,0x6a,0xa2,0x9b,0xc1,0x53,0x60,0x09,0xe8,0xa3,0xb8,0x9d,0xd7,0xad,
+ 0x1f,0x1c,0xb8,0xec,0x98,0x41,0xf0,0xf6,0x0e,0x80,0xfb,0xe4,0xff,0xdf,0x9d,0x10,0xa7,0xeb,0x00,0xba,0x5f,0x4a,0x8f,0x1a,
+ 0x3a,0x52,0xb4,0xea,0xbf,0x09,0x49,0x15,0x35,0x36,0x59,0x9a,0x0f,0x54,0xd2,0xb2,0x1b,0x7f,0x7e,0x5e,0x09,0xad,0x76,0x54,
+ 0x8a,0x74,0x6d,0xca,0xd2,0x05,0x67,0x2b,0x76,0xeb,0xff,0x98,0xb2,0x26,0x95,0x38,0x19,0x88,0x44,0x14,0xe5,0x0a,0x59,0xa2,
+ 0x6b,0xe7,0x22,0x3e,0x44,0x21,0xd2,0x3f,0x1c,0xc0,0x9b,0xed,0x7c,0x48,0xb2,0xd8,0x92,0x0c,0x91,0x4f,0x3c,0x66,0x94,0xaf,
+ 0x5d,0x02,0x53,0xeb,0x9e,0xe2,0x9e,0xe4,0xd3,0x1f,0x86,0x01,0x64,0x9c,0x00,0xc2,0xe9,0x5a,0x74,0x75,0x0d,0x3d,0xe1,0x79,
+ 0x88,0xbf,0x1c,0x01,0x97,0xc9,0x19,0x23,0x80,0xd7,0x36,0x5a,0x5f,0x96,0x16,0xb1,0x63,0x0c,0xc6,0x46,0x40,0x3b,0xce,0x5d,
+ 0x35,0xd4,0x59,0x3e,0x43,0x9a,0x18,0xae,0xc3,0xc9,0xcb,0xc3,0xfb,0x9b,0x13,0x5f,0x6a,0xb5,0xc7,0xe0,0xf3,0x05,0xc3,0x59,
+ 0xdf,0x27,0x62,0x2b,0xde,0x41,0xc9,0x53,0xb9,0xff,0x34,0x10,0x67,0xf6,0x26,0x32,0x98,0x7b,0xfe,0x5c,0x42,0x94,0x81,0x94,
+ 0x82,0x9d,0xac,0x0a,0x8b,0xc6,0x4b,0x15,0x4a,0xd3,0x98,0x90,0x45,0x60,0x33,0x80,0xe0,0x23,0xde,0xf8,0x03,0xa4,0xf6,0x45,
+ 0x47,0xe5,0xce,0xb8,0x03,0x42,0x47,0xe8,0x41,0x36,0x71,0x77,0xad,0xfd,0xa2,0xe8,0x97,0x74,0x4e,0x2e,0xda,0x1e,0x1d,0x8c,
+ 0x5a,0xc8,0x1e,0x9a,0xd5,0xc2,0xf0,0xc6,0x22,0xa8,0x4f,0x9b,0xbd,0xd8,0x1c,0x9a,0x51,0xc4,0x2f,0x9a,0xf6,0x5f,0xa7,0x27,
+ 0x97,0xba,0x96,0x2e,0x85,0x57,0xc0,0x60,0xe7,0x78,0x56,0x7f,0x6a,0xef,0xc2,0x95,0x9a,0x4b,0x11,0x02,0xc8,0x82,0x9c,0xc9,
+ 0x1a,0x05,0x7c,0xba,0x71,0xb5,0x4e,0x7a,0x99,0x6c,0xf4,0xe8,0x9e,0xd4,0x5a,0x98,0xc8,0x9f,0xbf,0x8d,0xbb,0x18,0x5c,0x43,
+ 0xf5,0xd0,0x2a,0xe8,0xe2,0x62,0xee,0x78,0x04,0xdb,0xbd,0xd1,0xfb,0x5b,0x0a,0xa8,0x70,0x7e,0xf0,0x97,0x84,0x78,0xe3,0x08,
+ 0x03,0x5d,0x47,0x2c,0x63,0xa8,0x25,0x38,0x97,0x01,0xd2,0x3f,0x3a,0xda,0xe5,0xe5,0xf6,0xe6,0x9b,0xdc,0x7e,0x2c,0xcc,0xff,
+ 0x17,0x4c,0x4d,0x00,0xa2,0xd8,0xd6,0x01,0x0e,0xb8,0x8b,0xee,0xe6,0xe0,0x72,0x55,0x89,0x2c,0x27,0x19,0x61,0xf6,0x77,0x01,
+ 0x8c,0x31,0x82,0x0f,0x9d,0x30,0x82,0x0f,0x99,0x02,0x01,0x01,0x30,0x26,0x30,0x12,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,
+ 0x03,0x13,0x07,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x02,0x10,0xd1,0x73,0x97,0xaa,0xa7,0x3a,0x31,0xa2,0x44,0xc0,0x4b,0x40,
+ 0x69,0x40,0x4b,0xfa,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0xa0,0x5e,0x30,0x10,0x06,
+ 0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x0c,0x31,0x02,0x30,0x00,0x30,0x19,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,
+ 0x0d,0x01,0x09,0x03,0x31,0x0c,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x04,0x30,0x2f,0x06,0x09,0x2a,0x86,
+ 0x48,0x86,0xf7,0x0d,0x01,0x09,0x04,0x31,0x22,0x04,0x20,0xcb,0xa1,0x2f,0x7b,0x0f,0x6a,0x14,0x06,0x26,0x77,0x7b,0xee,0xd1,
+ 0x90,0x34,0x1c,0xa7,0xcd,0x94,0x65,0xe0,0xe4,0x24,0x12,0x0c,0x4e,0xa2,0x89,0xeb,0x2d,0xe5,0xbb,0x30,0x0d,0x06,0x09,0x2a,
+ 0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x04,0x82,0x01,0x00,0x73,0xb7,0xdf,0xb4,0xd2,0x60,0x31,0x2d,0x14,0x63,
+ 0x71,0x87,0x5b,0xd9,0xee,0x66,0x85,0x88,0xbe,0x1e,0xc3,0x5e,0x30,0x25,0x62,0x05,0x66,0x6e,0x9b,0x51,0xaa,0x5b,0xee,0xed,
+ 0xe4,0x4c,0x83,0x19,0x7e,0x7b,0x78,0xe0,0x04,0xb5,0xdb,0xb3,0x48,0xba,0xa3,0xa4,0x54,0xb2,0x3e,0xe4,0x99,0xf1,0xb2,0x6e,
+ 0xb7,0x7a,0x44,0x76,0x11,0xb4,0x51,0xae,0xe3,0xec,0xc2,0x43,0x65,0xf5,0x95,0x1c,0x57,0x9e,0x4d,0x49,0x4d,0x4c,0xee,0x09,
+ 0xdd,0xdb,0xab,0xf3,0x14,0x89,0xec,0x6e,0x94,0xd2,0xac,0xd8,0xed,0xe3,0xbb,0x8a,0xf0,0x05,0x9d,0x1d,0xbe,0x8b,0x7f,0x34,
+ 0x63,0xe7,0x87,0x04,0x25,0x5a,0xff,0xc9,0xca,0xa9,0xab,0xd5,0xf2,0x16,0xf6,0x26,0x5d,0xf9,0xf9,0xbf,0xb4,0xce,0x86,0x55,
+ 0xd4,0x95,0x91,0x1e,0x12,0x25,0x36,0x43,0x37,0x6e,0x93,0x14,0xf0,0x86,0xad,0xc6,0x7d,0x07,0x86,0xe5,0x18,0x4f,0x3d,0xe3,
+ 0x92,0x67,0x7b,0x74,0xbf,0xa9,0x71,0x5a,0x49,0xcf,0xf5,0x60,0xf4,0x09,0x65,0x38,0xfd,0x13,0xe2,0x03,0x8a,0x84,0x17,0xc7,
+ 0x83,0x7a,0xd5,0x42,0x95,0x47,0xd8,0x9d,0x76,0x52,0xb5,0xbc,0x11,0x63,0x78,0x53,0x66,0x0e,0x95,0xc8,0xd4,0xfa,0x6e,0x3d,
+ 0x3b,0x1b,0x56,0xf2,0x98,0xc3,0x4c,0xc8,0xdc,0x1f,0x7e,0xa3,0x8b,0x1a,0x3b,0xa6,0x4d,0xed,0x70,0x75,0x55,0xcd,0x0c,0xf9,
+ 0x4e,0xfb,0xa6,0x84,0xcb,0xbc,0xf5,0x28,0x89,0x2e,0x30,0x07,0x8f,0x1d,0x8d,0x10,0x03,0x20,0xe9,0xb0,0x56,0x53,0x9d,0xf9,
+ 0x43,0xfb,0xba,0xb7,0x25,0x5d,0xa1,0x82,0x0d,0xe8,0x30,0x82,0x03,0x1c,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,
+ 0x06,0x31,0x82,0x03,0x0d,0x30,0x82,0x03,0x09,0x02,0x01,0x01,0x30,0x77,0x30,0x63,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,
+ 0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,
+ 0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x3b,0x30,0x39,0x06,0x03,0x55,0x04,0x03,0x13,0x32,0x44,0x69,0x67,0x69,0x43,0x65,0x72,
+ 0x74,0x20,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x47,0x34,0x20,0x52,0x53,0x41,0x34,0x30,0x39,0x36,0x20,0x53,0x48,0x41,
+ 0x32,0x35,0x36,0x20,0x54,0x69,0x6d,0x65,0x53,0x74,0x61,0x6d,0x70,0x69,0x6e,0x67,0x20,0x43,0x41,0x02,0x10,0x0c,0x4d,0x69,
+ 0x72,0x4b,0x94,0xfa,0x3c,0x2a,0x4a,0x3d,0x29,0x07,0x80,0x3d,0x5a,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,
+ 0x02,0x01,0x05,0x00,0xa0,0x69,0x30,0x18,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x03,0x31,0x0b,0x06,0x09,0x2a,
+ 0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0x30,0x1c,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x05,0x31,0x0f,0x17,
+ 0x0d,0x32,0x32,0x30,0x39,0x33,0x30,0x31,0x37,0x35,0x33,0x34,0x33,0x5a,0x30,0x2f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
+ 0x01,0x09,0x04,0x31,0x22,0x04,0x20,0xbf,0x5c,0x03,0xc6,0x50,0xb0,0xde,0xd1,0x96,0x6d,0x74,0x64,0xa4,0xda,0x0f,0x51,0x71,
+ 0x0f,0x5a,0x87,0x97,0x78,0x2e,0x17,0x99,0xc6,0xa2,0x7b,0xa7,0x9b,0x75,0xeb,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,
+ 0x0d,0x01,0x01,0x01,0x05,0x00,0x04,0x82,0x02,0x00,0x0e,0xb2,0xbf,0xf0,0xf2,0x35,0x55,0xc7,0x9d,0x49,0xce,0x0a,0xac,0x3a,
+ 0x6a,0xd8,0x85,0xa0,0x2b,0x81,0x97,0x85,0xc2,0x16,0x4d,0x6d,0x77,0x72,0xdf,0x2e,0x0a,0x6b,0x2e,0xbd,0xd6,0xb4,0x66,0x22,
+ 0x7b,0x43,0x1b,0x7e,0x7a,0x1b,0xdb,0x72,0xfb,0x1d,0xd5,0xe9,0x84,0x01,0xe1,0x64,0x15,0x05,0x0d,0xb5,0x85,0x1d,0x93,0xf0,
+ 0xcf,0x72,0x77,0x07,0x30,0x82,0xa9,0x6e,0x9c,0x5d,0xc9,0x39,0xda,0x19,0x9b,0xca,0x34,0x05,0xf0,0xe4,0xd7,0x02,0xbe,0x8a,
+ 0x5f,0x74,0x39,0xe6,0xe9,0xb4,0xdf,0x00,0x4a,0xeb,0xb4,0x0d,0xf6,0xb2,0x5b,0x7f,0x10,0xb1,0xef,0x05,0x53,0xfc,0x74,0x41,
+ 0x5b,0x83,0xeb,0xf9,0x37,0x9f,0x03,0xc2,0x1a,0x98,0x13,0xc9,0x6c,0x1c,0xd8,0x82,0xd8,0xd7,0xbf,0x13,0x07,0x20,0xf9,0xf2,
+ 0xea,0x96,0x46,0xb7,0x2d,0x51,0x2f,0xc3,0x40,0x12,0x3f,0x35,0xeb,0x88,0xfa,0x3c,0x66,0x30,0xd9,0x16,0xe2,0x4b,0x05,0x14,
+ 0x11,0x07,0x9a,0x64,0xc5,0x92,0x01,0xec,0xdb,0x5d,0x01,0x91,0x08,0x4f,0x1e,0xec,0x12,0xdd,0x7d,0xa0,0x32,0x5a,0x84,0x2a,
+ 0x7c,0xb9,0x25,0x34,0x57,0x12,0x0c,0x86,0x2d,0xcd,0x01,0x26,0x85,0x17,0x8c,0x7d,0x07,0x3f,0x2c,0x08,0xb6,0xac,0xc3,0xca,
+ 0x72,0x17,0xfe,0x4c,0xef,0xbb,0x69,0x20,0x11,0x33,0x63,0xf8,0xca,0x0a,0xe1,0x8c,0xf5,0x31,0x4e,0x83,0x87,0xfb,0xa9,0xd2,
+ 0x29,0x4b,0x82,0x84,0x27,0xfa,0x01,0x31,0x48,0xc1,0x25,0xe5,0x51,0x49,0xf5,0x52,0x60,0xdb,0x64,0x08,0x36,0xd2,0x2f,0x4e,
+ 0x7a,0x5d,0x92,0xee,0x06,0xec,0xe4,0x3b,0x5d,0xdc,0xc3,0x49,0xa1,0x8e,0x96,0xa6,0x17,0x00,0x2d,0x0d,0xee,0x6e,0x88,0x16,
+ 0x1e,0xea,0x9c,0x9b,0x55,0x9d,0xea,0x4a,0xa5,0xbb,0x54,0x33,0xaa,0x72,0x8c,0x5f,0xb7,0xe6,0x22,0xe9,0x1d,0xca,0xbc,0x6d,
+ 0xdf,0x7b,0x68,0xb5,0x71,0x3b,0x9f,0xfd,0x2b,0x53,0x35,0xa6,0xbb,0x78,0xf2,0x5a,0x41,0x69,0x52,0x5c,0x47,0xdc,0xf0,0x3e,
+ 0x06,0xef,0x60,0xb6,0xd3,0xb1,0x30,0xda,0x41,0xee,0x5a,0x2e,0x8e,0x24,0x0e,0x1e,0xcd,0x6c,0xa6,0x2e,0x9b,0x3c,0x77,0x02,
+ 0x21,0x86,0x16,0x68,0xfc,0xd6,0x64,0x84,0x46,0x1e,0xd1,0xe6,0x86,0x6f,0xee,0x5f,0x5c,0xca,0xb6,0xc9,0x9b,0xb8,0x03,0x46,
+ 0x1b,0x67,0x52,0x48,0x48,0x1c,0x07,0xad,0xbd,0x3c,0x2f,0x1b,0xd1,0xe3,0xb5,0xba,0x21,0x20,0x3b,0x6d,0xfb,0x30,0xa6,0x6d,
+ 0x2d,0xd7,0xb0,0x67,0xa4,0x19,0x0f,0x38,0xff,0xb0,0xad,0xf0,0xc3,0xb3,0xd7,0x7c,0x92,0xa0,0xe8,0x9c,0x22,0x60,0x0f,0x88,
+ 0x08,0xa7,0xf0,0xfa,0x90,0x45,0x2c,0x26,0xa6,0x88,0x25,0x24,0x7b,0x69,0x23,0x0b,0x20,0x04,0x89,0xd4,0x66,0x89,0x7d,0xb6,
+ 0x50,0x0e,0xb3,0xfe,0xf9,0xd0,0x91,0x2b,0x1d,0x17,0x62,0x6d,0xad,0x8e,0xf9,0x52,0x63,0x8f,0xe9,0x93,0xe6,0xea,0xb8,0xe6,
+ 0xce,0x0c,0x69,0xc9,0x47,0xd7,0x7e,0xb4,0x0d,0x49,0xbe,0xcb,0x05,0xe4,0xac,0x0b,0xd4,0xa1,0x6b,0x66,0x0f,0xff,0xe7,0x01,
+ 0x5a,0x91,0x05,0xa8,0xc0,0x2b,0xda,0xe9,0x5c,0x18,0xfb,0xe3,0x4d,0x60,0x0f,0x34,0x19,0x68,0x30,0x82,0x0a,0xc4,0x06,0x0a,
+ 0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x04,0x01,0x31,0x82,0x0a,0xb4,0x30,0x82,0x05,0x56,0x06,0x09,0x2a,0x86,0x48,0x86,
+ 0xf7,0x0d,0x01,0x07,0x02,0xa0,0x82,0x05,0x47,0x30,0x82,0x05,0x43,0x02,0x01,0x01,0x31,0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,
+ 0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x30,0x5c,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x04,0xa0,
+ 0x4e,0x30,0x4c,0x30,0x17,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x0f,0x30,0x09,0x03,0x01,0x00,0xa0,0x04,
+ 0xa2,0x02,0x80,0x00,0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20,0xdd,
+ 0x8b,0xd7,0x29,0x3b,0xae,0x16,0xec,0xbb,0x81,0x80,0x55,0x15,0xd8,0x87,0xa5,0x3e,0xeb,0x0b,0x74,0x59,0xb6,0x56,0xf1,0x0b,
+ 0x2e,0xe1,0xb4,0x42,0x4d,0x8b,0x18,0xa0,0x82,0x03,0x05,0x30,0x82,0x03,0x01,0x30,0x82,0x01,0xe9,0xa0,0x03,0x02,0x01,0x02,
+ 0x02,0x10,0x8d,0x01,0xec,0xa9,0x68,0x41,0x93,0x8f,0x40,0x42,0x93,0x4a,0x72,0x6b,0x03,0xcc,0x30,0x0d,0x06,0x09,0x2a,0x86,
+ 0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x30,0x12,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x03,0x13,0x07,0x54,0x65,
+ 0x73,0x74,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d,0x32,0x32,0x30,0x39,0x33,0x30,0x31,0x37,0x32,0x34,0x31,0x39,0x5a,0x17,0x0d,
+ 0x33,0x39,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,
+ 0x13,0x05,0x63,0x65,0x72,0x74,0x33,0x30,0x82,0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,
+ 0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xf4,0x21,0x90,0xec,0x4a,0x19,0xca,0xa7,
+ 0x1f,0x25,0x80,0x0b,0x92,0x21,0x2d,0x53,0xb4,0x25,0xa3,0x37,0x40,0xae,0xce,0xf1,0x46,0xf6,0xda,0x21,0xd3,0x54,0x8e,0x02,
+ 0x95,0xfe,0x37,0x3a,0xff,0xb9,0x36,0x88,0x70,0xf2,0x33,0x0c,0x5c,0x60,0x36,0xbf,0x8d,0x51,0xef,0x18,0x5d,0x47,0x68,0xbc,
+ 0xda,0xd8,0xf8,0x94,0xaf,0xcf,0xa6,0x48,0x61,0x78,0x04,0xcd,0x73,0x03,0xa0,0x6c,0xdb,0x24,0x94,0x20,0x54,0xbb,0x19,0xf2,
+ 0xb6,0xf9,0x0d,0xf4,0x31,0xbd,0x79,0xb5,0x98,0x12,0xc4,0x62,0x06,0xfb,0x16,0x08,0x51,0xa2,0xbf,0x12,0xcf,0x88,0xf4,0x4c,
+ 0x26,0xec,0x80,0xc7,0xa7,0xeb,0x89,0x24,0x6a,0xe4,0x1e,0x3a,0x1d,0x4a,0x7c,0x42,0xaa,0x03,0x5e,0x47,0xde,0x21,0xc4,0x06,
+ 0x86,0x57,0x0d,0xce,0xe0,0x27,0xf2,0x43,0x56,0x2a,0x60,0x1b,0x18,0xf5,0x03,0x91,0xa4,0xda,0x86,0x1c,0xcb,0x2c,0x2d,0x21,
+ 0x54,0xc5,0xd8,0xe2,0xe2,0x02,0x19,0xb0,0x73,0xe0,0xf8,0x95,0x5c,0x4f,0x1d,0x8f,0xd2,0xe0,0x4a,0x7c,0x20,0x9e,0x29,0xec,
+ 0x05,0x34,0xb0,0x4c,0x1a,0xaf,0x2a,0x01,0xf1,0x0f,0x26,0xdc,0x38,0x68,0x85,0xbd,0xc0,0x73,0xec,0x10,0x17,0x3a,0xd8,0x6d,
+ 0x33,0x3b,0xab,0xd3,0x79,0x61,0x2c,0xac,0x11,0xe1,0x09,0x5e,0xe0,0x7b,0xd3,0xc0,0xb8,0xf8,0xb5,0x9a,0x20,0x68,0xa7,0xf0,
+ 0x66,0x9b,0xc2,0xe8,0x83,0x14,0x7d,0x3c,0x7f,0x7a,0x85,0x95,0xc9,0x05,0x74,0xf4,0xee,0xa9,0x83,0x6a,0x55,0xa5,0x78,0xa8,
+ 0xa8,0xb4,0x6d,0xb1,0xab,0x49,0x50,0xd1,0x02,0x03,0x01,0x00,0x01,0xa3,0x55,0x30,0x53,0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,
+ 0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x43,0x06,0x03,0x55,0x1d,0x01,0x04,0x3c,0x30,0x3a,0x80,0x10,0x88,0x17,0xf7,0x38,
+ 0x65,0x8b,0x78,0x78,0xf6,0x77,0xe3,0x25,0x47,0x54,0x33,0x4c,0xa1,0x14,0x30,0x12,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,
+ 0x03,0x13,0x07,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x82,0x10,0x2b,0x59,0xb4,0xc7,0xe2,0xce,0x08,0x97,0x46,0x48,0x32,0x17,
+ 0x0f,0x97,0xc5,0x08,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x03,0x82,0x01,0x01,0x00,
+ 0x8e,0xe0,0xc9,0x58,0x24,0x1b,0x16,0x6a,0x8a,0x4f,0x67,0xac,0xd7,0x75,0x62,0x53,0x94,0xfc,0xeb,0x8b,0x36,0x2a,0x9f,0x9c,
+ 0x8b,0x8f,0x60,0x42,0xdd,0x37,0x13,0x10,0x5f,0x5a,0x52,0xc8,0xee,0x51,0x92,0x18,0xaf,0x84,0x18,0x5f,0x27,0x69,0xf4,0xde,
+ 0x22,0x4b,0x9c,0xaa,0x18,0x9e,0xde,0x04,0xc0,0xc4,0xfd,0x74,0x08,0x25,0x43,0xbf,0x00,0x1d,0xc2,0xd6,0xb2,0x4e,0xa4,0x4a,
+ 0x73,0xa1,0xff,0x71,0x3d,0xa5,0xf1,0x21,0xcf,0x4d,0xb4,0x5c,0x55,0x54,0x6f,0x94,0x50,0x21,0xbb,0x85,0xcb,0x54,0xeb,0x07,
+ 0xaf,0x74,0x62,0x21,0xf5,0x89,0x43,0xcb,0x10,0x62,0xd6,0xbe,0xc0,0x3a,0xb3,0x6b,0x9f,0x80,0xde,0xe0,0xc0,0x6e,0x8a,0x0a,
+ 0xe7,0x1f,0x08,0x9b,0x89,0x38,0xc2,0x30,0xfa,0xd9,0xc2,0x8c,0xf7,0xbd,0xbd,0xd4,0x6b,0x99,0xbd,0x5f,0x0e,0xb1,0x76,0xd6,
+ 0x5b,0x1f,0x1a,0xd7,0x27,0x5d,0x5b,0x19,0x1c,0x6d,0x5a,0x91,0x81,0x06,0x83,0x82,0x6d,0xaf,0x48,0x70,0x72,0x8b,0x7c,0x8e,
+ 0x57,0xcd,0x35,0x5d,0x7d,0x96,0xe5,0x2d,0x31,0xd2,0xa9,0xf8,0xad,0x9d,0x13,0xb4,0x89,0x75,0x7e,0xbc,0x39,0x11,0x27,0x9d,
+ 0xc3,0x7b,0xf1,0x40,0x2a,0x23,0xed,0x50,0xee,0x10,0x1b,0x97,0x13,0x71,0x1c,0x5a,0x7f,0x06,0xab,0x9b,0x51,0x2b,0x1f,0x85,
+ 0x27,0x99,0x11,0x18,0x62,0x97,0xcb,0x08,0x24,0x6d,0xf5,0x08,0x56,0xb5,0x36,0x00,0xf3,0x6b,0x3d,0xa9,0x13,0xd3,0xcf,0x0c,
+ 0x94,0x6f,0x9e,0x05,0x62,0xeb,0x9c,0x52,0x9d,0x0c,0x15,0x81,0x4d,0x7d,0xe3,0x2f,0x31,0x82,0x01,0xc4,0x30,0x82,0x01,0xc0,
+ 0x02,0x01,0x01,0x30,0x26,0x30,0x12,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x03,0x13,0x07,0x54,0x65,0x73,0x74,0x20,0x43,
+ 0x41,0x02,0x10,0x8d,0x01,0xec,0xa9,0x68,0x41,0x93,0x8f,0x40,0x42,0x93,0x4a,0x72,0x6b,0x03,0xcc,0x30,0x0d,0x06,0x09,0x60,
+ 0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0xa0,0x71,0x30,0x10,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x02,
+ 0x01,0x0c,0x31,0x02,0x30,0x00,0x30,0x11,0x06,0x0a,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x19,0x04,0x31,0x03,0x02,0x01,
+ 0x02,0x30,0x19,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x03,0x31,0x0c,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,
+ 0x37,0x02,0x01,0x04,0x30,0x2f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x04,0x31,0x22,0x04,0x20,0xcb,0xa1,0x2f,
+ 0x7b,0x0f,0x6a,0x14,0x06,0x26,0x77,0x7b,0xee,0xd1,0x90,0x34,0x1c,0xa7,0xcd,0x94,0x65,0xe0,0xe4,0x24,0x12,0x0c,0x4e,0xa2,
+ 0x89,0xeb,0x2d,0xe5,0xbb,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x04,0x82,0x01,0x00,
+ 0x68,0xfc,0x34,0xac,0x24,0xe1,0x93,0x00,0xec,0x8d,0x29,0xe1,0x32,0x03,0xe6,0x8a,0xd6,0x39,0x79,0x07,0x85,0x97,0xf4,0xb8,
+ 0x0c,0xf1,0x24,0xa0,0x16,0x09,0x0c,0xf8,0x02,0x40,0x94,0xdb,0x19,0x7a,0x6f,0x91,0xee,0x24,0x36,0x77,0x32,0x02,0xb5,0xd1,
+ 0xf9,0xe0,0xa2,0xdd,0xe0,0xe1,0x14,0x30,0x11,0xe1,0x25,0x02,0x0a,0x7c,0x10,0xdb,0xbd,0xb0,0x4e,0xbb,0x36,0xef,0x87,0xf0,
+ 0x17,0x49,0x77,0x45,0xa0,0x9e,0x47,0x70,0x1a,0xe2,0x87,0x39,0x41,0x24,0x1c,0xe0,0x09,0xb0,0xe0,0xfa,0xc5,0xf3,0xba,0xba,
+ 0x03,0x65,0x64,0xf9,0xa8,0x7d,0xe5,0x0e,0x84,0xc8,0xd1,0xe2,0xf5,0x44,0xa4,0x6f,0x33,0xac,0xbb,0x15,0x3b,0x0a,0x1a,0x04,
+ 0x6e,0xc2,0x54,0xa7,0x78,0x77,0x7d,0x32,0x21,0x4d,0x0c,0x3f,0x7b,0x0a,0x61,0x18,0x58,0xdb,0x59,0x02,0x3f,0xcf,0xb2,0xd0,
+ 0x5c,0xa5,0xea,0x96,0xd4,0x5c,0xd2,0x09,0xd3,0x18,0x61,0x73,0x6e,0x9f,0xdf,0xcb,0x17,0x4f,0xd1,0xc0,0xa2,0x2d,0x8b,0xf5,
+ 0x46,0xdf,0xf8,0xb8,0x4f,0x47,0x98,0xf4,0x44,0xa6,0xa1,0x5b,0xcb,0xfa,0xc1,0x31,0x4e,0xc4,0x03,0xea,0x06,0x1b,0x9b,0x94,
+ 0xa6,0xc8,0x1c,0x7a,0x69,0x3b,0x8d,0x8d,0x83,0x20,0x56,0x18,0xf1,0xe0,0xd2,0xfb,0xbc,0xaf,0xf7,0xdc,0x17,0x3b,0xcd,0xac,
+ 0x2b,0x07,0x86,0xc6,0x7f,0x25,0xc3,0xa2,0x6c,0x7c,0x49,0xa9,0xc1,0xe2,0x5e,0x40,0x05,0xfb,0x2f,0xab,0xd5,0x98,0x3a,0x69,
+ 0xbb,0x83,0x1c,0xbd,0xde,0x55,0xc0,0x74,0x71,0x8d,0xdb,0xc7,0x95,0xf4,0xf5,0xca,0x30,0x82,0x05,0x56,0x06,0x09,0x2a,0x86,
+ 0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,0x82,0x05,0x47,0x30,0x82,0x05,0x43,0x02,0x01,0x01,0x31,0x0f,0x30,0x0d,0x06,0x09,
+ 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x30,0x5c,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,
+ 0x04,0xa0,0x4e,0x30,0x4c,0x30,0x17,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x0f,0x30,0x09,0x03,0x01,0x00,
+ 0xa0,0x04,0xa2,0x02,0x80,0x00,0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,
+ 0x20,0xdd,0x8b,0xd7,0x29,0x3b,0xae,0x16,0xec,0xbb,0x81,0x80,0x55,0x15,0xd8,0x87,0xa5,0x3e,0xeb,0x0b,0x74,0x59,0xb6,0x56,
+ 0xf1,0x0b,0x2e,0xe1,0xb4,0x42,0x4d,0x8b,0x18,0xa0,0x82,0x03,0x05,0x30,0x82,0x03,0x01,0x30,0x82,0x01,0xe9,0xa0,0x03,0x02,
+ 0x01,0x02,0x02,0x10,0xae,0xfb,0x3e,0x08,0x15,0xa4,0xe3,0xa7,0x4d,0x91,0x6a,0x85,0x68,0x5b,0x58,0xa1,0x30,0x0d,0x06,0x09,
+ 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x30,0x12,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x03,0x13,0x07,
+ 0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d,0x32,0x32,0x30,0x39,0x33,0x30,0x31,0x37,0x32,0x33,0x30,0x33,0x5a,
+ 0x17,0x0d,0x33,0x39,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,
+ 0x04,0x03,0x13,0x05,0x63,0x65,0x72,0x74,0x32,0x30,0x82,0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
+ 0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xca,0x01,0x2f,0x98,0x69,0x71,
+ 0x64,0x63,0x56,0x38,0xd7,0xc4,0xad,0x64,0x02,0x34,0xd4,0x31,0xc2,0x27,0x5d,0xd7,0x8f,0x72,0xd0,0x70,0x95,0xd9,0x75,0x65,
+ 0x2e,0x8c,0x5b,0x76,0xcd,0x54,0x3f,0xd9,0x0a,0xcc,0x3f,0x03,0x8f,0x74,0x2b,0x8c,0x3d,0x3d,0x4c,0xd3,0xaa,0x3c,0x97,0xf1,
+ 0x44,0x46,0x57,0x92,0xa9,0xdd,0xd9,0xf0,0xc7,0x8b,0x39,0xf5,0x8d,0x28,0x41,0x18,0xaf,0xca,0x99,0xd1,0xf1,0xe4,0xab,0x93,
+ 0x0a,0xb6,0xd4,0xad,0x2b,0x9f,0x60,0x27,0x4c,0xf2,0xc9,0x14,0xde,0xf2,0xc6,0xbe,0x82,0x14,0x83,0x65,0x13,0x9f,0x9c,0x8d,
+ 0xfa,0xac,0x95,0x12,0x00,0xd0,0xa4,0x36,0x4d,0xf0,0x8f,0xfc,0x1a,0x43,0x47,0xc3,0xff,0xce,0x1b,0x24,0xd6,0xcf,0x63,0xd1,
+ 0x41,0x23,0xb8,0x62,0x5f,0x31,0x4e,0x30,0x3f,0x63,0x64,0xff,0x72,0xb5,0x9d,0xe5,0xaa,0x22,0xbc,0x1d,0xb3,0x23,0xc9,0x16,
+ 0x49,0x10,0xed,0x51,0x02,0xd2,0x90,0xc6,0x86,0x47,0x40,0x7e,0xf1,0xcf,0xc1,0x17,0xa0,0x72,0xaf,0x40,0xb1,0x23,0x3d,0x5a,
+ 0xa1,0xf9,0xed,0xc8,0xb6,0x66,0xa7,0x94,0x39,0x09,0x03,0x6d,0x16,0x4e,0xc4,0x2a,0x4b,0x1f,0x5b,0x22,0x39,0xf7,0x60,0x1c,
+ 0x71,0x65,0x4c,0x11,0x29,0x59,0x96,0x5e,0x9e,0xfe,0xaf,0x23,0xd1,0xe3,0x2c,0xce,0xd2,0x31,0x8c,0x80,0x29,0x6c,0x82,0x99,
+ 0xe8,0x68,0xbd,0x7e,0x66,0xaa,0x35,0x0c,0xae,0x61,0xde,0x59,0x7d,0x5b,0x16,0x09,0x07,0x52,0x6a,0x14,0x26,0x3c,0x48,0x3e,
+ 0x03,0xdb,0xd4,0x8a,0xea,0x0e,0x46,0x1a,0x24,0xbd,0x02,0x03,0x01,0x00,0x01,0xa3,0x55,0x30,0x53,0x30,0x0c,0x06,0x03,0x55,
+ 0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x43,0x06,0x03,0x55,0x1d,0x01,0x04,0x3c,0x30,0x3a,0x80,0x10,0x88,0x17,
+ 0xf7,0x38,0x65,0x8b,0x78,0x78,0xf6,0x77,0xe3,0x25,0x47,0x54,0x33,0x4c,0xa1,0x14,0x30,0x12,0x31,0x10,0x30,0x0e,0x06,0x03,
+ 0x55,0x04,0x03,0x13,0x07,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x82,0x10,0x2b,0x59,0xb4,0xc7,0xe2,0xce,0x08,0x97,0x46,0x48,
+ 0x32,0x17,0x0f,0x97,0xc5,0x08,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x03,0x82,0x01,
+ 0x01,0x00,0xd1,0x0d,0xdd,0x83,0x0c,0xd8,0xf9,0x0c,0x71,0xe3,0x2f,0x7c,0xc9,0xd7,0x8e,0x33,0x27,0xb6,0x6b,0x34,0x3c,0x41,
+ 0xf0,0x13,0x03,0xd6,0x5a,0xe2,0x55,0x12,0x42,0x06,0x20,0x03,0xb1,0x74,0xc7,0xc0,0x08,0x00,0x21,0xbe,0x90,0xe7,0xfd,0xac,
+ 0xe0,0x67,0x42,0xe7,0x53,0x86,0xcf,0x53,0x55,0x40,0xf1,0xbc,0xfc,0x87,0xab,0x67,0xb6,0x09,0xe1,0xf1,0xa2,0xce,0xf6,0xbf,
+ 0xe6,0x1d,0x43,0x4f,0x41,0xf0,0xf5,0xc0,0xfa,0xc5,0xd2,0x14,0x2d,0xd9,0x23,0x8e,0x9c,0xeb,0x68,0xff,0x3c,0x5f,0x18,0xca,
+ 0x4b,0x09,0xad,0xcd,0xbd,0x23,0x62,0x33,0x4e,0x02,0x10,0xf9,0xe3,0x68,0x6f,0x22,0xb0,0x86,0x0b,0x5a,0xbe,0xd3,0xee,0x8a,
+ 0x0b,0x4c,0x92,0x9e,0x06,0x31,0x1f,0x95,0x4f,0xbf,0x27,0x7f,0x1f,0xcd,0xcc,0x9c,0x70,0xa1,0x51,0x07,0x7a,0x09,0x36,0x3f,
+ 0x0a,0x2f,0x16,0x77,0x26,0x9b,0xb4,0xc9,0x1e,0x86,0xe3,0xb3,0xb7,0xc3,0xcc,0xf1,0x44,0x6e,0x2e,0xf4,0xc9,0x5b,0x23,0x08,
+ 0x0a,0xc0,0xdb,0xc1,0x1a,0x37,0xb3,0xb1,0x91,0xce,0x24,0x26,0x56,0x7f,0x26,0x37,0x88,0xa0,0x02,0x37,0x6e,0x9c,0xca,0xc1,
+ 0x8c,0x19,0x99,0xca,0x6c,0x9a,0x98,0x75,0x89,0xfc,0x6d,0x92,0xfc,0xb5,0x12,0x5b,0x29,0xb1,0x88,0x68,0x3b,0xef,0xf0,0xc0,
+ 0x8f,0x82,0x5e,0x33,0xf9,0x67,0x6b,0xe8,0x60,0x1b,0x14,0xec,0x9c,0xdf,0x21,0x38,0xbb,0x0d,0x3f,0xd9,0xbc,0xd2,0x01,0x2a,
+ 0x92,0x0c,0xc2,0x97,0x2e,0x12,0x22,0x54,0x76,0xeb,0x80,0x51,0x99,0x9d,0x0f,0x26,0x12,0xb7,0x31,0x82,0x01,0xc4,0x30,0x82,
+ 0x01,0xc0,0x02,0x01,0x01,0x30,0x26,0x30,0x12,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x03,0x13,0x07,0x54,0x65,0x73,0x74,
+ 0x20,0x43,0x41,0x02,0x10,0xae,0xfb,0x3e,0x08,0x15,0xa4,0xe3,0xa7,0x4d,0x91,0x6a,0x85,0x68,0x5b,0x58,0xa1,0x30,0x0d,0x06,
+ 0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0xa0,0x71,0x30,0x10,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,
+ 0x37,0x02,0x01,0x0c,0x31,0x02,0x30,0x00,0x30,0x11,0x06,0x0a,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x19,0x04,0x31,0x03,
+ 0x02,0x01,0x01,0x30,0x19,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x03,0x31,0x0c,0x06,0x0a,0x2b,0x06,0x01,0x04,
+ 0x01,0x82,0x37,0x02,0x01,0x04,0x30,0x2f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x04,0x31,0x22,0x04,0x20,0xcb,
+ 0xa1,0x2f,0x7b,0x0f,0x6a,0x14,0x06,0x26,0x77,0x7b,0xee,0xd1,0x90,0x34,0x1c,0xa7,0xcd,0x94,0x65,0xe0,0xe4,0x24,0x12,0x0c,
+ 0x4e,0xa2,0x89,0xeb,0x2d,0xe5,0xbb,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x04,0x82,
+ 0x01,0x00,0x26,0x76,0xb3,0xf2,0xc9,0xb1,0x73,0x13,0xb5,0xd2,0xc5,0xb7,0x01,0x5c,0xc6,0x94,0x38,0x9f,0xc7,0x57,0x56,0x95,
+ 0xb0,0xf4,0x6d,0xc2,0xd4,0x6a,0xf1,0x4d,0x09,0xa1,0x51,0xa6,0x91,0xf0,0x0e,0x84,0xc0,0x2c,0x74,0xa3,0x97,0x1f,0x41,0xe0,
+ 0x4a,0xfa,0x1a,0x78,0xa9,0xd5,0x3c,0x85,0x29,0x2b,0xaf,0xbb,0xc3,0x61,0x0d,0x50,0x20,0x20,0xf5,0x80,0x0d,0x6a,0x15,0x4b,
+ 0x38,0x6c,0x55,0xd9,0xf9,0xd0,0x44,0x22,0x46,0x98,0xe6,0x07,0xd4,0xba,0x3d,0x9d,0x50,0xa7,0x8e,0x1f,0xa8,0x82,0x25,0x7e,
+ 0x39,0xda,0xe1,0x49,0xc7,0x24,0x3f,0x31,0xfb,0x4b,0xba,0x75,0xdb,0x10,0x0a,0xbe,0xc5,0xad,0x3e,0x30,0x16,0x9b,0x15,0xbb,
+ 0xc0,0x59,0xf2,0xf5,0x4f,0xf5,0x56,0xc6,0x28,0xd0,0x1e,0x7d,0x8f,0x2e,0x2b,0xb6,0x76,0x94,0x52,0x87,0x99,0xa3,0x66,0x3d,
+ 0x94,0x0d,0x73,0xb0,0xd5,0xd4,0x76,0x5b,0x69,0x95,0x0a,0x16,0x4f,0x5c,0xf4,0x95,0x5b,0x42,0x45,0x04,0x5c,0x53,0xb7,0x1a,
+ 0x61,0x6c,0x82,0xdc,0x95,0x94,0x38,0x64,0x34,0x01,0x98,0x2e,0xf8,0xcf,0xf8,0x66,0xae,0xba,0xf8,0x70,0x9e,0x9e,0xde,0xa2,
+ 0x7f,0x56,0x8d,0xd9,0x6a,0x7b,0x41,0x02,0x46,0x05,0x5c,0xba,0xed,0x43,0x98,0x56,0x39,0x52,0xc0,0x0b,0x3c,0xe1,0x7d,0x1b,
+ 0xf5,0xac,0x03,0x5b,0xbb,0x7a,0x65,0x80,0x4b,0xcb,0xb7,0x51,0xa7,0x19,0x8a,0x38,0x75,0x76,0x75,0xc2,0x1f,0x12,0xc4,0x68,
+ 0x96,0xe0,0x89,0x9f,0x37,0x3d,0xab,0xfd,0x6b,0x03,0xb3,0xa1,0x51,0xf8,0x69,0x17,0xea,0xff,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+
static void call_winverify(WCHAR *pathW, LONG *status, BOOL hash_only)
{
static GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
@@ -1312,6 +1782,116 @@ static void test_get_known_usages(void)
"expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
}
+static void test_multiple_signatures(void)
+{
+ static const BYTE serials[][16] =
+ {
+ { 0xfa, 0x4b, 0x40, 0x69, 0x40, 0x4b, 0xc0, 0x44, 0xa2, 0x31, 0x3a, 0xa7, 0xaa, 0x97, 0x73, 0xd1, },
+ { 0xcc, 0x03, 0x6b, 0x72, 0x4a, 0x93, 0x42, 0x40, 0x8f, 0x93, 0x41, 0x68, 0xa9, 0xec, 0x01, 0x8d, },
+ { 0xa1, 0x58, 0x5b, 0x68, 0x85, 0x6a, 0x91, 0x4d, 0xa7, 0xe3, 0xa4, 0x15, 0x08, 0x3e, 0xfb, 0xae, },
+ };
+ static GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
+ WINTRUST_SIGNATURE_SETTINGS settings = { sizeof(settings) };
+ WINTRUST_FILE_INFO file_info = { sizeof(file_info) };
+ WINTRUST_DATA data = { sizeof(data) };
+ CRYPT_PROVIDER_DATA *prov;
+ WCHAR pathW[MAX_PATH];
+ CERT_INFO *cert_info;
+ unsigned int i;
+ BYTE buf[4096];
+ DWORD written;
+ LONG status;
+ HANDLE file;
+ DWORD size;
+ BOOL bret;
+
+ file = create_temp_file(pathW);
+ ok(file != INVALID_HANDLE_VALUE, "Failed to create temporary file.\n");
+ bret = WriteFile(file, self_signed_3certs, sizeof(self_signed_3certs), &written, NULL);
+ ok(bret, "Failed, err %lu.\n", GetLastError());
+ CloseHandle(file);
+
+ file_info.pcwszFilePath = pathW;
+ data.dwUIChoice = WTD_UI_NONE;
+ data.fdwRevocationChecks = WTD_REVOKE_NONE;
+ data.dwUnionChoice = WTD_CHOICE_FILE;
+ data.pFile = &file_info;
+ data.dwStateAction = WTD_STATEACTION_VERIFY;
+ data.dwProvFlags = 0;
+ data.pSignatureSettings = &settings;
+
+ settings.cSecondarySigs = 0xcccccccc;
+ settings.dwVerifiedSigIndex = 0xcccccccc;
+ status = WinVerifyTrust(NULL, &WVTPolicyGUID, &data);
+ todo_wine ok(status == CERT_E_UNTRUSTEDROOT || status == CERT_E_CHAINING, "Failed, ret %#lx\n", status);
+ ok(settings.cSecondarySigs == 0xcccccccc, "Got %lu.\n", settings.cSecondarySigs);
+ todo_wine ok(settings.dwVerifiedSigIndex == 2, "Got %lu.\n", settings.dwVerifiedSigIndex);
+
+ prov = (CRYPT_PROVIDER_DATA *)data.hWVTStateData;
+ ok(prov->cbStruct == sizeof(*prov), "Got size %lu.\n", prov->cbStruct);
+ ok(prov->csSigners == 1, "Got %lu.\n", prov->csSigners);
+ ok(prov->pSigSettings == &settings, "Got %p, expected %p.\n", prov->pSigSettings, &settings);
+ ok(!!prov->pSigState, "Got %p, expected %p.\n", prov->pSigSettings, &settings);
+ if (prov->cbStruct == sizeof(*prov) && prov->pSigState)
+ {
+ ok(prov->pSigState->cbStruct == sizeof(*prov->pSigState)
+ || broken(prov->pSigState->cbStruct == offsetof(CRYPT_PROVIDER_SIGSTATE, iAttemptCount)) /* Win7 */,
+ "Got %lu.\n", prov->pSigState->cbStruct);
+ ok(prov->pSigState->fSupportMultiSig, "Got %d.\n", prov->pSigState->fSupportMultiSig);
+ ok(prov->pSigState->dwCryptoPolicySupport == (WSS_SIGTRUST_SUPPORT | WSS_OBJTRUST_SUPPORT
+ | WSS_CERTTRUST_SUPPORT), "Got %#lx.\n", prov->pSigState->dwCryptoPolicySupport);
+ ok(prov->pSigState->cSecondarySigs == 2, "Got %lu.\n", prov->pSigState->cSecondarySigs);
+
+ size = sizeof(buf);
+ bret = CryptMsgGetParam(prov->pSigState->hPrimarySig, CMSG_SIGNER_CERT_INFO_PARAM, 0, buf, &size);
+ ok(bret, "Failed, err %#lx.\n", GetLastError());
+ cert_info = (CERT_INFO *)buf;
+ ok(cert_info->SerialNumber.cbData == sizeof(serials[0]), "Got %lu.\n", cert_info->SerialNumber.cbData);
+ ok(!memcmp(cert_info->SerialNumber.pbData, serials[0], sizeof(serials[0])), "Data does not match.\n");
+ for (i = 0; i < prov->pSigState->cSecondarySigs; ++i)
+ {
+ bret = CryptMsgGetParam(prov->pSigState->rhSecondarySigs[i], CMSG_SIGNER_CERT_INFO_PARAM, 0, buf, &size);
+ ok(bret, "Failed, err %#lx.\n", GetLastError());
+ ok(cert_info->SerialNumber.cbData == sizeof(serials[0]), "Got %lu.\n", cert_info->SerialNumber.cbData);
+ ok(!memcmp(cert_info->SerialNumber.pbData, serials[i + 1], sizeof(serials[0])), "Data does not match.\n");
+ }
+ }
+
+ data.dwStateAction = WTD_STATEACTION_CLOSE;
+ status = WinVerifyTrust(NULL, &WVTPolicyGUID, &data);
+ ok(status == S_OK, "Failed, ret %#lx\n", status);
+
+ data.dwStateAction = WTD_STATEACTION_VERIFY;
+ settings.dwFlags = WSS_GET_SECONDARY_SIG_COUNT;
+ settings.cSecondarySigs = 0xcccccccc;
+ settings.dwVerifiedSigIndex = 0xcccccccc;
+ status = WinVerifyTrust(NULL, &WVTPolicyGUID, &data);
+ todo_wine ok(status == CERT_E_UNTRUSTEDROOT || status == CERT_E_CHAINING, "Failed, ret %#lx\n", status);
+ ok(settings.cSecondarySigs == 2, "Got %lu.\n", settings.cSecondarySigs);
+ todo_wine ok(settings.dwVerifiedSigIndex == 2, "Got %lu.\n", settings.dwVerifiedSigIndex);
+
+ data.dwStateAction = WTD_STATEACTION_CLOSE;
+ status = WinVerifyTrust(NULL, &WVTPolicyGUID, &data);
+ ok(status == S_OK, "Failed, ret %#lx\n", status);
+
+ data.dwStateAction = WTD_STATEACTION_VERIFY;
+ settings.dwFlags = WSS_VERIFY_SPECIFIC | WSS_GET_SECONDARY_SIG_COUNT;
+ settings.cSecondarySigs = 0xcccccccc;
+ settings.dwVerifiedSigIndex = 0xcccccccc;
+ settings.dwIndex = 1;
+ status = WinVerifyTrust(NULL, &WVTPolicyGUID, &data);
+ todo_wine ok(status == CERT_E_UNTRUSTEDROOT || status == CERT_E_CHAINING, "Failed, ret %#lx\n", status);
+ ok(settings.cSecondarySigs == 2, "Got %lu.\n", settings.cSecondarySigs);
+ todo_wine ok(settings.dwVerifiedSigIndex == 1, "Got %lu.\n", settings.dwVerifiedSigIndex);
+ settings.dwIndex = 0;
+
+ data.dwStateAction = WTD_STATEACTION_CLOSE;
+ status = WinVerifyTrust(NULL, &WVTPolicyGUID, &data);
+ ok(status == S_OK, "Failed, ret %#lx\n", status);
+
+ DeleteFileW(pathW);
+}
+
START_TEST(softpub)
{
InitFunctionPtrs();
@@ -1320,4 +1900,5 @@ START_TEST(softpub)
test_wintrust();
test_wintrust_digest();
test_get_known_usages();
+ test_multiple_signatures();
}
diff --git a/dlls/wintrust/wintrust_main.c b/dlls/wintrust/wintrust_main.c
index 33695008b24..925ae7ca85a 100644
--- wine/dlls/wintrust/wintrust_main.c
+++ wine/dlls/wintrust/wintrust_main.c
@@ -294,6 +294,10 @@ static LONG WINTRUST_DefaultVerify(HWND hwnd, GUID *actionID,
data->hWVTStateData = provData;
provData->pWintrustData = data;
+
+ if (WVT_ISINSTRUCT(WINTRUST_DATA, data->cbStruct, pSignatureSettings))
+ provData->pSigSettings = data->pSignatureSettings;
+
if (hwnd == INVALID_HANDLE_VALUE)
provData->hWndParent = GetDesktopWindow();
else
diff --git a/include/wincrypt.h b/include/wincrypt.h
index db2c30c7d68..29735f6225d 100644
--- wine/include/wincrypt.h
+++ wine/include/wincrypt.h
@@ -21,8 +21,6 @@
#ifndef __WINE_WINCRYPT_H
#define __WINE_WINCRYPT_H
-#include "wine/winheader_enter.h"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -1088,6 +1086,7 @@ typedef struct _CERT_CHAIN_POLICY_STATUS {
#define CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG 0x00004000
#define CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG 0x00008000
#define MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG 0x00010000
+#define MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG 0x00020000
typedef struct _AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA {
DWORD cbSize;
@@ -3353,8 +3352,10 @@ typedef struct _CTL_FIND_SUBJECT_PARA
#define CERT_NAME_URL_TYPE 7
#define CERT_NAME_UPN_TYPE 8
-#define CERT_NAME_ISSUER_FLAG 0x00000001
-#define CERT_NAME_DISABLE_IE4_UTF8_FLAG 0x00010000
+#define CERT_NAME_ISSUER_FLAG 0x00000001
+#define CERT_NAME_SEARCH_ALL_NAMES_FLAG 0x00000002
+#define CERT_NAME_DISABLE_IE4_UTF8_FLAG 0x00010000
+#define CERT_NAME_STR_ENABLE_PUNYCODE_FLAG 0x00200000
/* CryptFormatObject flags */
#define CRYPT_FORMAT_STR_MULTI_LINE 0x0001
@@ -4695,6 +4696,4 @@ HRESULT WINAPI FindCertsByIssuer(PCERT_CHAIN pCertChains, DWORD *pcbCertChains,
}
#endif
-#include "wine/winheader_exit.h"
-
#endif
diff --git a/include/wintrust.h b/include/wintrust.h
index 28df37c1626..eeb149822b4 100644
--- wine/include/wintrust.h
+++ wine/include/wintrust.h
@@ -19,8 +19,6 @@
#ifndef __WINE_WINTRUST_H
#define __WINE_WINTRUST_H
-#include "wine/winheader_enter.h"
-
#include <wincrypt.h>
@@ -477,6 +475,8 @@ CRYPT_PROVIDER_SGNR * WINAPI WTHelperGetProvSignerFromChain(
CRYPT_PROVIDER_DATA * WINAPI WTHelperProvDataFromStateData(HANDLE hStateData);
CRYPT_PROVIDER_PRIVDATA * WINAPI WTHelperGetProvPrivateDataFromChain(CRYPT_PROVIDER_DATA *,GUID *);
+#define szOID_NESTED_SIGNATURE "1.3.6.1.4.1.311.2.4.1"
+
#define SPC_INDIRECT_DATA_OBJID "1.3.6.1.4.1.311.2.1.4"
#define SPC_SP_AGENCY_INFO_OBJID "1.3.6.1.4.1.311.2.1.10"
#define SPC_STATEMENT_TYPE_OBJID "1.3.6.1.4.1.311.2.1.11"
@@ -664,6 +664,4 @@ typedef struct _WIN_TRUST_SUBJECT_FILE_AND_DISPLAY
}
#endif
-#include "wine/winheader_exit.h"
-
#endif
--
2.39.2 (Apple Git-144)
diff --git a/configure b/configure
index 24f958073a0..cdf99fc287d 100755
--- wine/configure
+++ wine/configure
@@ -950,6 +950,7 @@ enable_amstream
enable_apisetschema
enable_apphelp
enable_appwiz_cpl
+enable_atiadlxx
enable_api_ms_win_core_psm_appnotify_l1_1_0
enable_api_ms_win_power_base_l1_1_0
enable_atl
@@ -21778,6 +21779,7 @@ wine_fn_config_makefile dlls/apisetschema enable_apisetschema
wine_fn_config_makefile dlls/apphelp enable_apphelp
wine_fn_config_makefile dlls/apphelp/tests enable_tests
wine_fn_config_makefile dlls/appwiz.cpl enable_appwiz_cpl
+wine_fn_config_makefile dlls/atiadlxx enable_atiadlxx
wine_fn_config_makefile dlls/api-ms-win-core-psm-appnotify-l1-1-0 enable_api_ms_win_core_psm_appnotify_l1_1_0
wine_fn_config_makefile dlls/api-ms-win-power-base-l1-1-0 enable_api_ms_win_power_base_l1_1_0
wine_fn_config_makefile dlls/atl enable_atl
diff --git a/configure.ac b/configure.ac
index 58063421cce..c05d5b6f539 100644
--- wine/configure.ac
+++ wine/configure.ac
@@ -2424,6 +2424,7 @@ WINE_CONFIG_MAKEFILE(dlls/apisetschema)
WINE_CONFIG_MAKEFILE(dlls/apphelp)
WINE_CONFIG_MAKEFILE(dlls/apphelp/tests)
WINE_CONFIG_MAKEFILE(dlls/appwiz.cpl)
+WINE_CONFIG_MAKEFILE(dlls/atiadlxx)
WINE_CONFIG_MAKEFILE(dlls/api-ms-win-power-base-l1-1-0)
WINE_CONFIG_MAKEFILE(dlls/atl)
WINE_CONFIG_MAKEFILE(dlls/atl/tests)
diff --git a/dlls/atiadlxx/Makefile.in b/dlls/atiadlxx/Makefile.in
new file mode 100644
index 00000000000..fd9b8abf626
--- /dev/null
+++ wine/dlls/atiadlxx/Makefile.in
@@ -0,0 +1,8 @@
+EXTRADEFS = -DWINE_NO_LONG_TYPES
+MODULE = atiadlxx.dll
+IMPORTS = dxgi
+
+EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native
+
+C_SRCS = \
+ atiadlxx_main.c
diff --git a/dlls/atiadlxx/atiadlxx.spec b/dlls/atiadlxx/atiadlxx.spec
new file mode 100644
index 00000000000..1e447f38ded
--- /dev/null
+++ wine/dlls/atiadlxx/atiadlxx.spec
@@ -0,0 +1,1138 @@
+@ stub ADL2_ADC_CurrentProfileFromDrv_Get
+@ stub ADL2_ADC_Display_AdapterDeviceProfileEx_Get
+@ stub ADL2_ADC_DrvDataToProfile_Copy
+@ stub ADL2_ADC_FindClosestMode_Get
+@ stub ADL2_ADC_IsDevModeEqual_Get
+@ stub ADL2_ADC_Profile_Apply
+@ stub ADL2_APO_AudioDelayAdjustmentInfo_Get
+@ stub ADL2_APO_AudioDelay_Restore
+@ stub ADL2_APO_AudioDelay_Set
+@ stub ADL2_AdapterLimitation_Caps
+@ stub ADL2_AdapterX2_Caps
+@ stub ADL2_Adapter_AMDAndNonAMDDIsplayClone_Get
+@ stub ADL2_Adapter_ASICFamilyType_Get
+@ stub ADL2_Adapter_ASICInfo_Get
+@ stub ADL2_Adapter_Accessibility_Get
+@ stub ADL2_Adapter_AceDefaults_Restore
+@ stub ADL2_Adapter_Active_Get
+@ stub ADL2_Adapter_Active_Set
+@ stub ADL2_Adapter_Active_SetPrefer
+@ stub ADL2_Adapter_AdapterInfoX2_Get
+@ stub ADL2_Adapter_AdapterInfoX3_Get
+@ stub ADL2_Adapter_AdapterInfoX4_Get
+@ stub ADL2_Adapter_AdapterInfo_Get
+@ stub ADL2_Adapter_AdapterList_Disable
+@ stub ADL2_Adapter_AdapterLocationPath_Get
+@ stub ADL2_Adapter_Aspects_Get
+@ stub ADL2_Adapter_AudioChannelSplitConfiguration_Get
+@ stub ADL2_Adapter_AudioChannelSplit_Disable
+@ stub ADL2_Adapter_AudioChannelSplit_Enable
+@ stub ADL2_Adapter_BigSw_Info_Get
+@ stub ADL2_Adapter_BlackAndWhiteLevelSupport_Get
+@ stub ADL2_Adapter_BlackAndWhiteLevel_Get
+@ stub ADL2_Adapter_BlackAndWhiteLevel_Set
+@ stub ADL2_Adapter_BoardLayout_Get
+@ stub ADL2_Adapter_Caps
+@ stub ADL2_Adapter_ChipSetInfo_Get
+@ stub ADL2_Adapter_CloneTypes_Get
+@ stub ADL2_Adapter_ConfigMemory_Cap
+@ stub ADL2_Adapter_ConfigMemory_Get
+@ stub ADL2_Adapter_ConfigureState_Get
+@ stub ADL2_Adapter_ConnectionData_Get
+@ stub ADL2_Adapter_ConnectionData_Remove
+@ stub ADL2_Adapter_ConnectionData_Set
+@ stub ADL2_Adapter_ConnectionState_Get
+@ stub ADL2_Adapter_CrossDisplayPlatformInfo_Get
+@ stub ADL2_Adapter_CrossGPUClone_Disable
+@ stub ADL2_Adapter_CrossdisplayAdapterRole_Caps
+@ stub ADL2_Adapter_CrossdisplayInfoX2_Set
+@ stub ADL2_Adapter_CrossdisplayInfo_Get
+@ stub ADL2_Adapter_CrossdisplayInfo_Set
+@ stub ADL2_Adapter_CrossfireX2_Get
+@ stub ADL2_Adapter_Crossfire_Caps
+@ stub ADL2_Adapter_Crossfire_Get
+@ stub ADL2_Adapter_Crossfire_Set
+@ stub ADL2_Adapter_DefaultAudioChannelTable_Load
+@ stub ADL2_Adapter_Desktop_Caps
+@ stub ADL2_Adapter_Desktop_SupportedSLSGridTypes_Get
+@ stub ADL2_Adapter_DeviceID_Get
+@ stub ADL2_Adapter_DisplayAudioEndpoint_Enable
+@ stub ADL2_Adapter_DisplayAudioEndpoint_Mute
+@ stub ADL2_Adapter_DisplayAudioInfo_Get
+@ stub ADL2_Adapter_DisplayGTCCaps_Get
+@ stub ADL2_Adapter_Display_Caps
+@ stub ADL2_Adapter_DriverSettings_Get
+@ stub ADL2_Adapter_DriverSettings_Set
+@ stub ADL2_Adapter_ECC_ErrorInjection_Set
+@ stub ADL2_Adapter_ECC_ErrorRecords_Get
+@ stub ADL2_Adapter_EDC_ErrorInjection_Set
+@ stub ADL2_Adapter_EDC_ErrorRecords_Get
+@ stub ADL2_Adapter_EDIDManagement_Caps
+@ stub ADL2_Adapter_EmulationMode_Set
+@ stub ADL2_Adapter_ExtInfo_Get
+@ stub ADL2_Adapter_Feature_Caps
+@ stub ADL2_Adapter_FrameMetrics_Caps
+@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Disable
+@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Enable
+@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Get
+@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Start
+@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Stop
+@ stub ADL2_Adapter_FrameMetrics_Get
+@ stub ADL2_Adapter_FrameMetrics_Start
+@ stub ADL2_Adapter_FrameMetrics_Stop
+@ stub ADL2_Adapter_Gamma_Get
+@ stub ADL2_Adapter_Gamma_Set
+@ stub ADL2_Adapter_Graphic_Core_Info_Get
+@ stub ADL2_Adapter_HBC_Caps
+@ stub ADL2_Adapter_HBM_ECC_UC_Check
+@ stub ADL2_Adapter_Headless_Get
+@ stub ADL2_Adapter_ID_Get
+@ stub ADL2_Adapter_IsGamingDriver_Info_Get
+@ stub ADL2_Adapter_LocalDisplayConfig_Get
+@ stub ADL2_Adapter_LocalDisplayConfig_Set
+@ stub ADL2_Adapter_LocalDisplayState_Get
+@ stub ADL2_Adapter_MVPU_Set
+@ stub ADL2_Adapter_MaxCursorSize_Get
+@ stub ADL2_Adapter_MemoryInfo2_Get
+@ stub ADL2_Adapter_MemoryInfo_Get
+@ stub ADL2_Adapter_MirabilisSupport_Get
+@ stub ADL2_Adapter_ModeSwitch
+@ stub ADL2_Adapter_ModeTimingOverride_Caps
+@ stub ADL2_Adapter_Modes_ReEnumerate
+@ stub ADL2_Adapter_NumberOfActivatableSources_Get
+@ stdcall ADL2_Adapter_NumberOfAdapters_Get(ptr ptr)
+@ stub ADL2_Adapter_ObservedClockInfo_Get
+@ stub ADL2_Adapter_PMLog_Start
+@ stub ADL2_Adapter_PMLog_Stop
+@ stub ADL2_Adapter_PMLog_Support_Get
+@ stub ADL2_Adapter_PreFlipPostProcessing_Disable
+@ stub ADL2_Adapter_PreFlipPostProcessing_Enable
+@ stub ADL2_Adapter_PreFlipPostProcessing_Get_Status
+@ stub ADL2_Adapter_PreFlipPostProcessing_Select_LUT_Algorithm
+@ stub ADL2_Adapter_PreFlipPostProcessing_Select_LUT_Buffer
+@ stub ADL2_Adapter_PreFlipPostProcessing_Unselect_LUT_Buffer
+@ stub ADL2_Adapter_Primary_Get
+@ stub ADL2_Adapter_Primary_Set
+@ stub ADL2_Adapter_RAS_ErrorInjection_Set
+@ stub ADL2_Adapter_RegValueInt_Get
+@ stub ADL2_Adapter_RegValueInt_Set
+@ stub ADL2_Adapter_RegValueString_Get
+@ stub ADL2_Adapter_RegValueString_Set
+@ stub ADL2_Adapter_SWInfo_Get
+@ stub ADL2_Adapter_Speed_Caps
+@ stub ADL2_Adapter_Speed_Get
+@ stub ADL2_Adapter_Speed_Set
+@ stub ADL2_Adapter_SupportedConnections_Get
+@ stub ADL2_Adapter_TRNG_Get
+@ stub ADL2_Adapter_Tear_Free_Cap
+@ stub ADL2_Adapter_VRAMUsage_Get
+@ stub ADL2_Adapter_VariBrightEnable_Set
+@ stub ADL2_Adapter_VariBrightLevel_Get
+@ stub ADL2_Adapter_VariBrightLevel_Set
+@ stub ADL2_Adapter_VariBright_Caps
+@ stub ADL2_Adapter_VerndorID_Int_get
+@ stub ADL2_Adapter_VideoBiosInfo_Get
+@ stub ADL2_Adapter_VideoTheaterModeInfo_Get
+@ stub ADL2_Adapter_VideoTheaterModeInfo_Set
+@ stub ADL2_Adapter_XConnectSupport_Get
+@ stub ADL2_ApplicationProfilesX2_AppInterceptionList_Set
+@ stub ADL2_ApplicationProfilesX2_AppStartStopInfo_Get
+@ stub ADL2_ApplicationProfiles_AppInterceptionList_Set
+@ stub ADL2_ApplicationProfiles_AppInterception_Set
+@ stub ADL2_ApplicationProfiles_AppStartStopInfo_Get
+@ stub ADL2_ApplicationProfiles_AppStartStop_Resume
+@ stub ADL2_ApplicationProfiles_Applications_Get
+@ stub ADL2_ApplicationProfiles_ConvertToCompact
+@ stub ADL2_ApplicationProfiles_DriverAreaPrivacy_Get
+@ stub ADL2_ApplicationProfiles_GetCustomization
+@ stub ADL2_ApplicationProfiles_HitListsX2_Get
+@ stub ADL2_ApplicationProfiles_HitListsX3_Get
+@ stub ADL2_ApplicationProfiles_HitLists_Get
+@ stub ADL2_ApplicationProfiles_ProfileApplicationX2_Assign
+@ stub ADL2_ApplicationProfiles_ProfileApplication_Assign
+@ stub ADL2_ApplicationProfiles_ProfileOfAnApplicationX2_Search
+@ stub ADL2_ApplicationProfiles_ProfileOfAnApplication_InMemorySearch
+@ stub ADL2_ApplicationProfiles_ProfileOfAnApplication_Search
+@ stub ADL2_ApplicationProfiles_Profile_Create
+@ stub ADL2_ApplicationProfiles_Profile_Exist
+@ stub ADL2_ApplicationProfiles_Profile_Remove
+@ stub ADL2_ApplicationProfiles_PropertyType_Get
+@ stub ADL2_ApplicationProfiles_Release_Get
+@ stub ADL2_ApplicationProfiles_RemoveApplication
+@ stub ADL2_ApplicationProfiles_StatusInfo_Get
+@ stub ADL2_ApplicationProfiles_System_Reload
+@ stub ADL2_ApplicationProfiles_User_Load
+@ stub ADL2_ApplicationProfiles_User_Unload
+@ stub ADL2_Audio_CurrentSampleRate_Get
+@ stub ADL2_AutoTuningResult_Get
+@ stub ADL2_BOOST_Settings_Get
+@ stub ADL2_BOOST_Settings_Set
+@ stub ADL2_Blockchain_BlockchainMode_Caps
+@ stub ADL2_Blockchain_BlockchainMode_Get
+@ stub ADL2_Blockchain_BlockchainMode_Set
+@ stub ADL2_Blockchain_Hashrate_Set
+@ stub ADL2_CDS_UnsafeMode_Set
+@ stub ADL2_CHILL_SettingsX2_Get
+@ stub ADL2_CHILL_SettingsX2_Set
+@ stub ADL2_CV_DongleSettings_Get
+@ stub ADL2_CV_DongleSettings_Reset
+@ stub ADL2_CV_DongleSettings_Set
+@ stub ADL2_Chill_Caps_Get
+@ stub ADL2_Chill_Settings_Get
+@ stub ADL2_Chill_Settings_Notify
+@ stub ADL2_Chill_Settings_Set
+@ stub ADL2_CustomFan_Caps
+@ stub ADL2_CustomFan_Get
+@ stub ADL2_CustomFan_Set
+@ stub ADL2_DELAG_Settings_Get
+@ stub ADL2_DELAG_Settings_Set
+@ stub ADL2_DFP_AllowOnlyCETimings_Get
+@ stub ADL2_DFP_AllowOnlyCETimings_Set
+@ stub ADL2_DFP_BaseAudioSupport_Get
+@ stub ADL2_DFP_GPUScalingEnable_Get
+@ stub ADL2_DFP_GPUScalingEnable_Set
+@ stub ADL2_DFP_HDMISupport_Get
+@ stub ADL2_DFP_MVPUAnalogSupport_Get
+@ stub ADL2_DFP_PixelFormat_Caps
+@ stub ADL2_DFP_PixelFormat_Get
+@ stub ADL2_DFP_PixelFormat_Set
+@ stub ADL2_DVRSupport_Get
+@ stub ADL2_Desktop_DOPP_Enable
+@ stub ADL2_Desktop_DOPP_EnableX2
+@ stub ADL2_Desktop_Detach
+@ stub ADL2_Desktop_Device_Create
+@ stub ADL2_Desktop_Device_Destroy
+@ stub ADL2_Desktop_ExclusiveModeX2_Get
+@ stub ADL2_Desktop_HardwareCursor_SetBitmap
+@ stub ADL2_Desktop_HardwareCursor_SetPosition
+@ stub ADL2_Desktop_HardwareCursor_Toggle
+@ stub ADL2_Desktop_PFPAComplete_Set
+@ stub ADL2_Desktop_PFPAState_Get
+@ stub ADL2_Desktop_PrimaryInfo_Get
+@ stub ADL2_Desktop_TextureState_Get
+@ stub ADL2_Desktop_Texture_Enable
+@ stub ADL2_Device_PMLog_Device_Create
+@ stub ADL2_Device_PMLog_Device_Destroy
+@ stub ADL2_DisplayScaling_Set
+@ stub ADL2_Display_AdapterID_Get
+@ stub ADL2_Display_AdjustCaps_Get
+@ stub ADL2_Display_AdjustmentCoherent_Get
+@ stub ADL2_Display_AdjustmentCoherent_Set
+@ stub ADL2_Display_AudioMappingInfo_Get
+@ stub ADL2_Display_AvivoColor_Get
+@ stub ADL2_Display_AvivoCurrentColor_Set
+@ stub ADL2_Display_AvivoDefaultColor_Set
+@ stub ADL2_Display_BackLight_Get
+@ stub ADL2_Display_BackLight_Set
+@ stub ADL2_Display_BezelOffsetSteppingSize_Get
+@ stub ADL2_Display_BezelOffset_Set
+@ stub ADL2_Display_BezelSupported_Validate
+@ stub ADL2_Display_Capabilities_Get
+@ stub ADL2_Display_ColorCaps_Get
+@ stub ADL2_Display_ColorDepth_Get
+@ stub ADL2_Display_ColorDepth_Set
+@ stub ADL2_Display_ColorTemperatureSourceDefault_Get
+@ stub ADL2_Display_ColorTemperatureSource_Get
+@ stub ADL2_Display_ColorTemperatureSource_Set
+@ stub ADL2_Display_Color_Get
+@ stub ADL2_Display_Color_Set
+@ stub ADL2_Display_ConnectedDisplays_Get
+@ stub ADL2_Display_ContainerID_Get
+@ stub ADL2_Display_ControllerOverlayAdjustmentCaps_Get
+@ stub ADL2_Display_ControllerOverlayAdjustmentData_Get
+@ stub ADL2_Display_ControllerOverlayAdjustmentData_Set
+@ stub ADL2_Display_CustomizedModeListNum_Get
+@ stub ADL2_Display_CustomizedModeList_Get
+@ stub ADL2_Display_CustomizedMode_Add
+@ stub ADL2_Display_CustomizedMode_Delete
+@ stub ADL2_Display_CustomizedMode_Validate
+@ stub ADL2_Display_DCE_Get
+@ stub ADL2_Display_DCE_Set
+@ stub ADL2_Display_DDCBlockAccess_Get
+@ stub ADL2_Display_DDCInfo2_Get
+@ stub ADL2_Display_DDCInfo_Get
+@ stub ADL2_Display_Deflicker_Get
+@ stub ADL2_Display_Deflicker_Set
+@ stub ADL2_Display_DeviceConfig_Get
+@ stub ADL2_Display_DisplayContent_Cap
+@ stub ADL2_Display_DisplayContent_Get
+@ stub ADL2_Display_DisplayContent_Set
+@ stub ADL2_Display_DisplayInfo_Get
+@ stub ADL2_Display_DisplayMapConfigX2_Set
+@ stub ADL2_Display_DisplayMapConfig_Get
+@ stub ADL2_Display_DisplayMapConfig_PossibleAddAndRemove
+@ stub ADL2_Display_DisplayMapConfig_Set
+@ stub ADL2_Display_DisplayMapConfig_Validate
+@ stub ADL2_Display_DitherState_Get
+@ stub ADL2_Display_DitherState_Set
+@ stub ADL2_Display_Downscaling_Caps
+@ stub ADL2_Display_DpMstAuxMsg_Get
+@ stub ADL2_Display_DpMstInfo_Get
+@ stub ADL2_Display_DummyVirtual_Destroy
+@ stub ADL2_Display_DummyVirtual_Get
+@ stub ADL2_Display_EdidData_Get
+@ stub ADL2_Display_EdidData_Set
+@ stub ADL2_Display_EnumDisplays_Get
+@ stub ADL2_Display_FilterSVideo_Get
+@ stub ADL2_Display_FilterSVideo_Set
+@ stub ADL2_Display_ForcibleDisplay_Get
+@ stub ADL2_Display_ForcibleDisplay_Set
+@ stub ADL2_Display_FormatsOverride_Get
+@ stub ADL2_Display_FormatsOverride_Set
+@ stub ADL2_Display_FreeSyncState_Get
+@ stub ADL2_Display_FreeSyncState_Set
+@ stub ADL2_Display_FreeSync_Cap
+@ stub ADL2_Display_GamutMapping_Get
+@ stub ADL2_Display_GamutMapping_Reset
+@ stub ADL2_Display_GamutMapping_Set
+@ stub ADL2_Display_Gamut_Caps
+@ stub ADL2_Display_Gamut_Get
+@ stub ADL2_Display_Gamut_Set
+@ stub ADL2_Display_HDCP_Get
+@ stub ADL2_Display_HDCP_Set
+@ stub ADL2_Display_HDRState_Get
+@ stub ADL2_Display_HDRState_Set
+@ stub ADL2_Display_ImageExpansion_Get
+@ stub ADL2_Display_ImageExpansion_Set
+@ stub ADL2_Display_InfoPacket_Get
+@ stub ADL2_Display_InfoPacket_Set
+@ stub ADL2_Display_IsVirtual_Get
+@ stub ADL2_Display_LCDRefreshRateCapability_Get
+@ stub ADL2_Display_LCDRefreshRateOptions_Get
+@ stub ADL2_Display_LCDRefreshRateOptions_Set
+@ stub ADL2_Display_LCDRefreshRate_Get
+@ stub ADL2_Display_LCDRefreshRate_Set
+@ stub ADL2_Display_Limits_Get
+@ stub ADL2_Display_MVPUCaps_Get
+@ stub ADL2_Display_MVPUStatus_Get
+@ stub ADL2_Display_ModeTimingOverrideInfo_Get
+@ stub ADL2_Display_ModeTimingOverrideListX2_Get
+@ stub ADL2_Display_ModeTimingOverrideListX3_Get
+@ stub ADL2_Display_ModeTimingOverrideList_Get
+@ stub ADL2_Display_ModeTimingOverrideX2_Get
+@ stub ADL2_Display_ModeTimingOverrideX2_Set
+@ stub ADL2_Display_ModeTimingOverrideX3_Get
+@ stub ADL2_Display_ModeTimingOverride_Delete
+@ stub ADL2_Display_ModeTimingOverride_Get
+@ stub ADL2_Display_ModeTimingOverride_Set
+@ stub ADL2_Display_Modes_Get
+@ stub ADL2_Display_Modes_Set
+@ stub ADL2_Display_Modes_X2_Get
+@ stub ADL2_Display_MonitorPowerState_Set
+@ stub ADL2_Display_NativeAUXChannel_Access
+@ stub ADL2_Display_NeedWorkaroundFor5Clone_Get
+@ stub ADL2_Display_NumberOfDisplays_Get
+@ stub ADL2_Display_ODClockConfig_Set
+@ stub ADL2_Display_ODClockInfo_Get
+@ stub ADL2_Display_Overlap_NotifyAdjustment
+@ stub ADL2_Display_Overlap_Set
+@ stub ADL2_Display_Overscan_Get
+@ stub ADL2_Display_Overscan_Set
+@ stub ADL2_Display_PixelFormatDefault_Get
+@ stub ADL2_Display_PixelFormat_Get
+@ stub ADL2_Display_PixelFormat_Set
+@ stub ADL2_Display_Position_Get
+@ stub ADL2_Display_Position_Set
+@ stub ADL2_Display_PossibleMapping_Get
+@ stub ADL2_Display_PossibleMode_Get
+@ stub ADL2_Display_PowerXpressActiveGPU_Get
+@ stub ADL2_Display_PowerXpressActiveGPU_Set
+@ stub ADL2_Display_PowerXpressActvieGPUR2_Get
+@ stub ADL2_Display_PowerXpressVersion_Get
+@ stub ADL2_Display_PowerXpress_AutoSwitchConfig_Get
+@ stub ADL2_Display_PowerXpress_AutoSwitchConfig_Set
+@ stub ADL2_Display_PreferredMode_Get
+@ stub ADL2_Display_PreservedAspectRatio_Get
+@ stub ADL2_Display_PreservedAspectRatio_Set
+@ stub ADL2_Display_Property_Get
+@ stub ADL2_Display_Property_Set
+@ stub ADL2_Display_RcDisplayAdjustment
+@ stub ADL2_Display_ReGammaCoefficients_Get
+@ stub ADL2_Display_ReGammaCoefficients_Set
+@ stub ADL2_Display_ReducedBlanking_Get
+@ stub ADL2_Display_ReducedBlanking_Set
+@ stub ADL2_Display_RegammaR1_Get
+@ stub ADL2_Display_RegammaR1_Set
+@ stub ADL2_Display_Regamma_Get
+@ stub ADL2_Display_Regamma_Set
+@ stub ADL2_Display_SLSBuilder_CommonMode_Get
+@ stub ADL2_Display_SLSBuilder_Create
+@ stub ADL2_Display_SLSBuilder_DisplaysCanBeNextCandidateInSLS_Get
+@ stub ADL2_Display_SLSBuilder_DisplaysCanBeNextCandidateToEnabled_Get
+@ stub ADL2_Display_SLSBuilder_Get
+@ stub ADL2_Display_SLSBuilder_IsActive_Notify
+@ stub ADL2_Display_SLSBuilder_MaxSLSLayoutSize_Get
+@ stub ADL2_Display_SLSBuilder_TimeOut_Get
+@ stub ADL2_Display_SLSBuilder_Update
+@ stub ADL2_Display_SLSGrid_Caps
+@ stub ADL2_Display_SLSMapConfigX2_Delete
+@ stub ADL2_Display_SLSMapConfigX2_Get
+@ stub ADL2_Display_SLSMapConfig_Create
+@ stub ADL2_Display_SLSMapConfig_Delete
+@ stub ADL2_Display_SLSMapConfig_Get
+@ stub ADL2_Display_SLSMapConfig_ImageCropType_Set
+@ stub ADL2_Display_SLSMapConfig_Rearrange
+@ stub ADL2_Display_SLSMapConfig_SetState
+@ stub ADL2_Display_SLSMapConfig_SupportedImageCropType_Get
+@ stub ADL2_Display_SLSMapConfig_Valid
+@ stub ADL2_Display_SLSMapIndexList_Get
+@ stub ADL2_Display_SLSMapIndex_Get
+@ stub ADL2_Display_SLSMiddleMode_Get
+@ stub ADL2_Display_SLSMiddleMode_Set
+@ stub ADL2_Display_SLSRecords_Get
+@ stub ADL2_Display_Sharpness_Caps
+@ stub ADL2_Display_Sharpness_Get
+@ stub ADL2_Display_Sharpness_Info_Get
+@ stub ADL2_Display_Sharpness_Set
+@ stub ADL2_Display_Size_Get
+@ stub ADL2_Display_Size_Set
+@ stub ADL2_Display_SourceContentAttribute_Get
+@ stub ADL2_Display_SourceContentAttribute_Set
+@ stub ADL2_Display_SplitDisplay_Caps
+@ stub ADL2_Display_SplitDisplay_Get
+@ stub ADL2_Display_SplitDisplay_RestoreDesktopConfiguration
+@ stub ADL2_Display_SplitDisplay_Set
+@ stub ADL2_Display_SupportedColorDepth_Get
+@ stub ADL2_Display_SupportedPixelFormat_Get
+@ stub ADL2_Display_SwitchingCapability_Get
+@ stub ADL2_Display_TVCaps_Get
+@ stub ADL2_Display_TargetTimingX2_Get
+@ stub ADL2_Display_TargetTiming_Get
+@ stub ADL2_Display_UnderScan_Auto_Get
+@ stub ADL2_Display_UnderScan_Auto_Set
+@ stub ADL2_Display_UnderscanState_Get
+@ stub ADL2_Display_UnderscanState_Set
+@ stub ADL2_Display_UnderscanSupport_Get
+@ stub ADL2_Display_Underscan_Get
+@ stub ADL2_Display_Underscan_Set
+@ stub ADL2_Display_Vector_Get
+@ stub ADL2_Display_ViewPort_Cap
+@ stub ADL2_Display_ViewPort_Get
+@ stub ADL2_Display_ViewPort_Set
+@ stub ADL2_Display_VirtualType_Get
+@ stub ADL2_Display_WriteAndReadI2C
+@ stub ADL2_Display_WriteAndReadI2CLargePayload
+@ stub ADL2_Display_WriteAndReadI2CRev_Get
+@ stub ADL2_ElmCompatibilityMode_Caps
+@ stub ADL2_ElmCompatibilityMode_Status_Get
+@ stub ADL2_ElmCompatibilityMode_Status_Set
+@ stub ADL2_ExclusiveModeGet
+@ stub ADL2_FPS_Caps
+@ stub ADL2_FPS_Settings_Get
+@ stub ADL2_FPS_Settings_Reset
+@ stub ADL2_FPS_Settings_Set
+@ stub ADL2_Feature_Settings_Get
+@ stub ADL2_Feature_Settings_Set
+@ stub ADL2_Flush_Driver_Data
+@ stub ADL2_GPUVMPageSize_Info_Get
+@ stub ADL2_GPUVMPageSize_Info_Set
+@ stub ADL2_GPUVerInfo_Get
+@ stub ADL2_GcnAsicInfo_Get
+@ stub ADL2_Graphics_IsDetachableGraphicsPlatform_Get
+@ stub ADL2_Graphics_IsGfx9AndAbove
+@ stub ADL2_Graphics_MantleVersion_Get
+@ stub ADL2_Graphics_Platform_Get
+@ stdcall ADL2_Graphics_VersionsX2_Get(ptr ptr)
+@ stub ADL2_Graphics_Versions_Get
+@ stub ADL2_Graphics_VulkanVersion_Get
+@ stub ADL2_HybridGraphicsGPU_Set
+@ stub ADL2_MGPUSLS_Status_Set
+@ stub ADL2_MMD_FeatureList_Get
+@ stub ADL2_MMD_FeatureValuesX2_Get
+@ stub ADL2_MMD_FeatureValuesX2_Set
+@ stub ADL2_MMD_FeatureValues_Get
+@ stub ADL2_MMD_FeatureValues_Set
+@ stub ADL2_MMD_FeaturesX2_Caps
+@ stub ADL2_MMD_Features_Caps
+@ stub ADL2_MMD_VideoAdjustInfo_Get
+@ stub ADL2_MMD_VideoAdjustInfo_Set
+@ stub ADL2_MMD_VideoColor_Caps
+@ stub ADL2_MMD_VideoColor_Get
+@ stub ADL2_MMD_VideoColor_Set
+@ stub ADL2_MMD_Video_Caps
+@ stub ADL2_Main_ControlX2_Create
+@ stdcall ADL2_Main_Control_Create(ptr long ptr)
+@ stub ADL2_Main_Control_Destroy
+@ stub ADL2_Main_Control_GetProcAddress
+@ stub ADL2_Main_Control_IsFunctionValid
+@ stub ADL2_Main_Control_Refresh
+@ stub ADL2_Main_LogDebug_Set
+@ stub ADL2_Main_LogError_Set
+@ stub ADL2_New_QueryPMLogData_Get
+@ stub ADL2_Overdrive5_CurrentActivity_Get
+@ stub ADL2_Overdrive5_FanSpeedInfo_Get
+@ stub ADL2_Overdrive5_FanSpeedToDefault_Set
+@ stub ADL2_Overdrive5_FanSpeed_Get
+@ stub ADL2_Overdrive5_FanSpeed_Set
+@ stub ADL2_Overdrive5_ODParameters_Get
+@ stub ADL2_Overdrive5_ODPerformanceLevels_Get
+@ stub ADL2_Overdrive5_ODPerformanceLevels_Set
+@ stub ADL2_Overdrive5_PowerControlAbsValue_Caps
+@ stub ADL2_Overdrive5_PowerControlAbsValue_Get
+@ stub ADL2_Overdrive5_PowerControlAbsValue_Set
+@ stub ADL2_Overdrive5_PowerControlInfo_Get
+@ stub ADL2_Overdrive5_PowerControl_Caps
+@ stub ADL2_Overdrive5_PowerControl_Get
+@ stub ADL2_Overdrive5_PowerControl_Set
+@ stub ADL2_Overdrive5_Temperature_Get
+@ stub ADL2_Overdrive5_ThermalDevices_Enum
+@ stub ADL2_Overdrive6_AdvancedFan_Caps
+@ stub ADL2_Overdrive6_CapabilitiesEx_Get
+@ stub ADL2_Overdrive6_Capabilities_Get
+@ stub ADL2_Overdrive6_ControlI2C
+@ stub ADL2_Overdrive6_CurrentPower_Get
+@ stub ADL2_Overdrive6_CurrentStatus_Get
+@ stub ADL2_Overdrive6_FanPWMLimitData_Get
+@ stub ADL2_Overdrive6_FanPWMLimitData_Set
+@ stub ADL2_Overdrive6_FanPWMLimitRangeInfo_Get
+@ stub ADL2_Overdrive6_FanSpeed_Get
+@ stub ADL2_Overdrive6_FanSpeed_Reset
+@ stub ADL2_Overdrive6_FanSpeed_Set
+@ stub ADL2_Overdrive6_FuzzyController_Caps
+@ stub ADL2_Overdrive6_MaxClockAdjust_Get
+@ stub ADL2_Overdrive6_PowerControlInfo_Get
+@ stub ADL2_Overdrive6_PowerControlInfo_Get_X2
+@ stub ADL2_Overdrive6_PowerControl_Caps
+@ stub ADL2_Overdrive6_PowerControl_Get
+@ stub ADL2_Overdrive6_PowerControl_Set
+@ stub ADL2_Overdrive6_StateEx_Get
+@ stub ADL2_Overdrive6_StateEx_Set
+@ stub ADL2_Overdrive6_StateInfo_Get
+@ stub ADL2_Overdrive6_State_Reset
+@ stub ADL2_Overdrive6_State_Set
+@ stub ADL2_Overdrive6_TargetTemperatureData_Get
+@ stub ADL2_Overdrive6_TargetTemperatureData_Set
+@ stub ADL2_Overdrive6_TargetTemperatureRangeInfo_Get
+@ stub ADL2_Overdrive6_TemperatureEx_Get
+@ stub ADL2_Overdrive6_Temperature_Get
+@ stub ADL2_Overdrive6_ThermalController_Caps
+@ stub ADL2_Overdrive6_ThermalLimitUnlock_Get
+@ stub ADL2_Overdrive6_ThermalLimitUnlock_Set
+@ stub ADL2_Overdrive6_VoltageControlInfo_Get
+@ stub ADL2_Overdrive6_VoltageControl_Get
+@ stub ADL2_Overdrive6_VoltageControl_Set
+@ stub ADL2_Overdrive8_Current_SettingX2_Get
+@ stub ADL2_Overdrive8_Current_SettingX3_Get
+@ stub ADL2_Overdrive8_Current_Setting_Get
+@ stub ADL2_Overdrive8_Init_SettingX2_Get
+@ stub ADL2_Overdrive8_Init_Setting_Get
+@ stub ADL2_Overdrive8_PMLogSenorRange_Caps
+@ stub ADL2_Overdrive8_PMLogSenorType_Support_Get
+@ stub ADL2_Overdrive8_PMLog_ShareMemory_Read
+@ stub ADL2_Overdrive8_PMLog_ShareMemory_Start
+@ stub ADL2_Overdrive8_PMLog_ShareMemory_Stop
+@ stub ADL2_Overdrive8_PMLog_ShareMemory_Support
+@ stub ADL2_Overdrive8_Setting_Set
+@ stub ADL2_OverdriveN_AutoWattman_Caps
+@ stub ADL2_OverdriveN_AutoWattman_Get
+@ stub ADL2_OverdriveN_AutoWattman_Set
+@ stub ADL2_OverdriveN_CapabilitiesX2_Get
+@ stub ADL2_OverdriveN_Capabilities_Get
+@ stub ADL2_OverdriveN_CountOfEvents_Get
+@ stub ADL2_OverdriveN_FanControl_Get
+@ stub ADL2_OverdriveN_FanControl_Set
+@ stub ADL2_OverdriveN_MemoryClocksX2_Get
+@ stub ADL2_OverdriveN_MemoryClocksX2_Set
+@ stub ADL2_OverdriveN_MemoryClocks_Get
+@ stub ADL2_OverdriveN_MemoryClocks_Set
+@ stub ADL2_OverdriveN_MemoryTimingLevel_Get
+@ stub ADL2_OverdriveN_MemoryTimingLevel_Set
+@ stub ADL2_OverdriveN_PerformanceStatus_Get
+@ stub ADL2_OverdriveN_PowerLimit_Get
+@ stub ADL2_OverdriveN_PowerLimit_Set
+@ stub ADL2_OverdriveN_SCLKAutoOverClock_Get
+@ stub ADL2_OverdriveN_SCLKAutoOverClock_Set
+@ stub ADL2_OverdriveN_SettingsExt_Get
+@ stub ADL2_OverdriveN_SettingsExt_Set
+@ stub ADL2_OverdriveN_SystemClocksX2_Get
+@ stub ADL2_OverdriveN_SystemClocksX2_Set
+@ stub ADL2_OverdriveN_SystemClocks_Get
+@ stub ADL2_OverdriveN_SystemClocks_Set
+@ stub ADL2_OverdriveN_Temperature_Get
+@ stub ADL2_OverdriveN_Test_Set
+@ stub ADL2_OverdriveN_ThrottleNotification_Get
+@ stub ADL2_OverdriveN_ZeroRPMFan_Get
+@ stub ADL2_OverdriveN_ZeroRPMFan_Set
+@ stub ADL2_Overdrive_Caps
+@ stub ADL2_PPLogSettings_Get
+@ stub ADL2_PPLogSettings_Set
+@ stub ADL2_PPW_Caps
+@ stub ADL2_PPW_Status_Get
+@ stub ADL2_PPW_Status_Set
+@ stub ADL2_PageMigration_Settings_Get
+@ stub ADL2_PageMigration_Settings_Set
+@ stub ADL2_PerGPU_GDEvent_Register
+@ stub ADL2_PerGPU_GDEvent_UnRegister
+@ stub ADL2_PerfTuning_Status_Get
+@ stub ADL2_PerfTuning_Status_Set
+@ stub ADL2_PerformanceTuning_Caps
+@ stub ADL2_PowerStates_Get
+@ stub ADL2_PowerXpress_AncillaryDevices_Get
+@ stub ADL2_PowerXpress_Config_Caps
+@ stub ADL2_PowerXpress_Configuration_Get
+@ stub ADL2_PowerXpress_ExtendedBatteryMode_Caps
+@ stub ADL2_PowerXpress_ExtendedBatteryMode_Get
+@ stub ADL2_PowerXpress_ExtendedBatteryMode_Set
+@ stub ADL2_PowerXpress_LongIdleDetect_Get
+@ stub ADL2_PowerXpress_LongIdleDetect_Set
+@ stub ADL2_PowerXpress_PowerControlMode_Get
+@ stub ADL2_PowerXpress_PowerControlMode_Set
+@ stub ADL2_PowerXpress_Scheme_Get
+@ stub ADL2_PowerXpress_Scheme_Set
+@ stub ADL2_RIS_Settings_Get
+@ stub ADL2_RIS_Settings_Set
+@ stub ADL2_RegisterEvent
+@ stub ADL2_RegisterEventX2
+@ stub ADL2_Remap
+@ stub ADL2_RemoteDisplay_Destroy
+@ stub ADL2_RemoteDisplay_Display_Acquire
+@ stub ADL2_RemoteDisplay_Display_Release
+@ stub ADL2_RemoteDisplay_Display_Release_All
+@ stub ADL2_RemoteDisplay_Hdcp20_Create
+@ stub ADL2_RemoteDisplay_Hdcp20_Destroy
+@ stub ADL2_RemoteDisplay_Hdcp20_Notify
+@ stub ADL2_RemoteDisplay_Hdcp20_Process
+@ stub ADL2_RemoteDisplay_IEPort_Set
+@ stub ADL2_RemoteDisplay_Initialize
+@ stub ADL2_RemoteDisplay_Nofitiation_Register
+@ stub ADL2_RemoteDisplay_Notification_UnRegister
+@ stub ADL2_RemoteDisplay_Support_Caps
+@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_InUse_Get
+@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_Info_Get
+@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_RadioState_Get
+@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Change
+@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Get
+@ stub ADL2_RemoteDisplay_WFDDeviceInfo_Get
+@ stub ADL2_RemoteDisplay_WFDDeviceName_Change
+@ stub ADL2_RemoteDisplay_WFDDevice_StatusInfo_Get
+@ stub ADL2_RemoteDisplay_WFDDiscover_Start
+@ stub ADL2_RemoteDisplay_WFDDiscover_Stop
+@ stub ADL2_RemoteDisplay_WFDLink_Connect
+@ stub ADL2_RemoteDisplay_WFDLink_Creation_Accept
+@ stub ADL2_RemoteDisplay_WFDLink_Disconnect
+@ stub ADL2_RemoteDisplay_WFDLink_WPS_Process
+@ stub ADL2_RemoteDisplay_WFDWDSPSettings_Set
+@ stub ADL2_RemoteDisplay_WirelessDisplayEnableDisable_Commit
+@ stub ADL2_RemotePlay_ControlFlags_Set
+@ stub ADL2_ScreenPoint_AudioMappingInfo_Get
+@ stub ADL2_Send
+@ stub ADL2_SendX2
+@ stub ADL2_Stereo3D_2DPackedFormat_Set
+@ stub ADL2_Stereo3D_3DCursorOffset_Get
+@ stub ADL2_Stereo3D_3DCursorOffset_Set
+@ stub ADL2_Stereo3D_CurrentFormat_Get
+@ stub ADL2_Stereo3D_Info_Get
+@ stub ADL2_Stereo3D_Modes_Get
+@ stub ADL2_SwitchableGraphics_Applications_Get
+@ stub ADL2_TV_Standard_Get
+@ stub ADL2_TV_Standard_Set
+@ stub ADL2_TurboSyncSupport_Get
+@ stub ADL2_UnRegisterEvent
+@ stub ADL2_UnRegisterEventX2
+@ stub ADL2_User_Settings_Notify
+@ stub ADL2_WS_Overdrive_Caps
+@ stub ADL2_Win_IsHybridAI
+@ stub ADL2_Workstation_8BitGrayscale_Get
+@ stub ADL2_Workstation_8BitGrayscale_Set
+@ stub ADL2_Workstation_AdapterNumOfGLSyncConnectors_Get
+@ stub ADL2_Workstation_Caps
+@ stub ADL2_Workstation_DeepBitDepthX2_Get
+@ stub ADL2_Workstation_DeepBitDepthX2_Set
+@ stub ADL2_Workstation_DeepBitDepth_Get
+@ stub ADL2_Workstation_DeepBitDepth_Set
+@ stub ADL2_Workstation_DisplayGLSyncMode_Get
+@ stub ADL2_Workstation_DisplayGLSyncMode_Set
+@ stub ADL2_Workstation_DisplayGenlockCapable_Get
+@ stub ADL2_Workstation_ECCData_Get
+@ stub ADL2_Workstation_ECCX2_Get
+@ stub ADL2_Workstation_ECC_Caps
+@ stub ADL2_Workstation_ECC_Get
+@ stub ADL2_Workstation_ECC_Set
+@ stub ADL2_Workstation_GLSyncCounters_Get
+@ stub ADL2_Workstation_GLSyncGenlockConfiguration_Get
+@ stub ADL2_Workstation_GLSyncGenlockConfiguration_Set
+@ stub ADL2_Workstation_GLSyncModuleDetect_Get
+@ stub ADL2_Workstation_GLSyncModuleInfo_Get
+@ stub ADL2_Workstation_GLSyncPortState_Get
+@ stub ADL2_Workstation_GLSyncPortState_Set
+@ stub ADL2_Workstation_GLSyncSupportedTopology_Get
+@ stub ADL2_Workstation_GlobalEDIDPersistence_Get
+@ stub ADL2_Workstation_GlobalEDIDPersistence_Set
+@ stub ADL2_Workstation_LoadBalancing_Caps
+@ stub ADL2_Workstation_LoadBalancing_Get
+@ stub ADL2_Workstation_LoadBalancing_Set
+@ stub ADL2_Workstation_RAS_ErrorCounts_Get
+@ stub ADL2_Workstation_RAS_ErrorCounts_Reset
+@ stub ADL2_Workstation_SDISegmentList_Get
+@ stub ADL2_Workstation_SDI_Caps
+@ stub ADL2_Workstation_SDI_Get
+@ stub ADL2_Workstation_SDI_Set
+@ stub ADL2_Workstation_Stereo_Get
+@ stub ADL2_Workstation_Stereo_Set
+@ stub ADL2_Workstation_UnsupportedDisplayModes_Enable
+@ stub ADL_ADC_CurrentProfileFromDrv_Get
+@ stub ADL_ADC_Display_AdapterDeviceProfileEx_Get
+@ stub ADL_ADC_DrvDataToProfile_Copy
+@ stub ADL_ADC_FindClosestMode_Get
+@ stub ADL_ADC_IsDevModeEqual_Get
+@ stub ADL_ADC_Profile_Apply
+@ stub ADL_APO_AudioDelayAdjustmentInfo_Get
+@ stub ADL_APO_AudioDelay_Restore
+@ stub ADL_APO_AudioDelay_Set
+@ stub ADL_AdapterLimitation_Caps
+@ stub ADL_AdapterX2_Caps
+@ stdcall ADL_Adapter_ASICFamilyType_Get(long ptr ptr)
+@ stub ADL_Adapter_ASICInfo_Get
+@ stub ADL_Adapter_Accessibility_Get
+@ stub ADL_Adapter_Active_Get
+@ stub ADL_Adapter_Active_Set
+@ stub ADL_Adapter_Active_SetPrefer
+@ stub ADL_Adapter_AdapterInfoX2_Get
+@ stdcall ADL_Adapter_AdapterInfo_Get(ptr long)
+@ stub ADL_Adapter_AdapterList_Disable
+@ stub ADL_Adapter_Aspects_Get
+@ stub ADL_Adapter_AudioChannelSplitConfiguration_Get
+@ stub ADL_Adapter_AudioChannelSplit_Disable
+@ stub ADL_Adapter_AudioChannelSplit_Enable
+@ stub ADL_Adapter_BigSw_Info_Get
+@ stub ADL_Adapter_BlackAndWhiteLevelSupport_Get
+@ stub ADL_Adapter_BlackAndWhiteLevel_Get
+@ stub ADL_Adapter_BlackAndWhiteLevel_Set
+@ stub ADL_Adapter_BoardLayout_Get
+@ stub ADL_Adapter_Caps
+@ stub ADL_Adapter_ChipSetInfo_Get
+@ stub ADL_Adapter_ConfigMemory_Cap
+@ stub ADL_Adapter_ConfigMemory_Get
+@ stub ADL_Adapter_ConfigureState_Get
+@ stub ADL_Adapter_ConnectionData_Get
+@ stub ADL_Adapter_ConnectionData_Remove
+@ stub ADL_Adapter_ConnectionData_Set
+@ stub ADL_Adapter_ConnectionState_Get
+@ stub ADL_Adapter_CrossDisplayPlatformInfo_Get
+@ stub ADL_Adapter_CrossdisplayAdapterRole_Caps
+@ stub ADL_Adapter_CrossdisplayInfoX2_Set
+@ stub ADL_Adapter_CrossdisplayInfo_Get
+@ stub ADL_Adapter_CrossdisplayInfo_Set
+@ stub ADL_Adapter_CrossfireX2_Get
+@ stdcall ADL_Adapter_Crossfire_Caps(long ptr ptr ptr)
+@ stdcall ADL_Adapter_Crossfire_Get(long ptr ptr)
+@ stub ADL_Adapter_Crossfire_Set
+@ stub ADL_Adapter_DefaultAudioChannelTable_Load
+@ stub ADL_Adapter_DisplayAudioEndpoint_Enable
+@ stub ADL_Adapter_DisplayAudioEndpoint_Mute
+@ stub ADL_Adapter_DisplayAudioInfo_Get
+@ stub ADL_Adapter_DisplayGTCCaps_Get
+@ stub ADL_Adapter_Display_Caps
+@ stub ADL_Adapter_DriverSettings_Get
+@ stub ADL_Adapter_DriverSettings_Set
+@ stub ADL_Adapter_EDIDManagement_Caps
+@ stub ADL_Adapter_EmulationMode_Set
+@ stub ADL_Adapter_ExtInfo_Get
+@ stub ADL_Adapter_Gamma_Get
+@ stub ADL_Adapter_Gamma_Set
+@ stub ADL_Adapter_ID_Get
+@ stub ADL_Adapter_LocalDisplayConfig_Get
+@ stub ADL_Adapter_LocalDisplayConfig_Set
+@ stub ADL_Adapter_LocalDisplayState_Get
+@ stub ADL_Adapter_MaxCursorSize_Get
+@ stub ADL_Adapter_MemoryInfo2_Get
+@ stdcall ADL_Adapter_MemoryInfo_Get(long ptr)
+@ stub ADL_Adapter_MirabilisSupport_Get
+@ stub ADL_Adapter_ModeSwitch
+@ stub ADL_Adapter_ModeTimingOverride_Caps
+@ stub ADL_Adapter_Modes_ReEnumerate
+@ stub ADL_Adapter_NumberOfActivatableSources_Get
+@ stdcall ADL_Adapter_NumberOfAdapters_Get(ptr)
+@ stdcall ADL_Adapter_ObservedClockInfo_Get(long ptr ptr)
+@ stub ADL_Adapter_ObservedGameClockInfo_Get
+@ stub ADL_Adapter_Primary_Get
+@ stub ADL_Adapter_Primary_Set
+@ stub ADL_Adapter_RegValueInt_Get
+@ stub ADL_Adapter_RegValueInt_Set
+@ stub ADL_Adapter_RegValueString_Get
+@ stub ADL_Adapter_RegValueString_Set
+@ stub ADL_Adapter_SWInfo_Get
+@ stub ADL_Adapter_Speed_Caps
+@ stub ADL_Adapter_Speed_Get
+@ stub ADL_Adapter_Speed_Set
+@ stub ADL_Adapter_SupportedConnections_Get
+@ stub ADL_Adapter_Tear_Free_Cap
+@ stub ADL_Adapter_VariBrightEnable_Set
+@ stub ADL_Adapter_VariBrightLevel_Get
+@ stub ADL_Adapter_VariBrightLevel_Set
+@ stub ADL_Adapter_VariBright_Caps
+@ stub ADL_Adapter_VideoBiosInfo_Get
+@ stub ADL_Adapter_VideoTheaterModeInfo_Get
+@ stub ADL_Adapter_VideoTheaterModeInfo_Set
+@ stub ADL_ApplicationProfiles_Applications_Get
+@ stub ADL_ApplicationProfiles_ConvertToCompact
+@ stub ADL_ApplicationProfiles_DriverAreaPrivacy_Get
+@ stub ADL_ApplicationProfiles_GetCustomization
+@ stub ADL_ApplicationProfiles_HitListsX2_Get
+@ stub ADL_ApplicationProfiles_HitLists_Get
+@ stub ADL_ApplicationProfiles_ProfileApplicationX2_Assign
+@ stub ADL_ApplicationProfiles_ProfileApplication_Assign
+@ stub ADL_ApplicationProfiles_ProfileOfAnApplicationX2_Search
+@ stub ADL_ApplicationProfiles_ProfileOfAnApplication_InMemorySearch
+@ stub ADL_ApplicationProfiles_ProfileOfAnApplication_Search
+@ stub ADL_ApplicationProfiles_Profile_Create
+@ stub ADL_ApplicationProfiles_Profile_Exist
+@ stub ADL_ApplicationProfiles_Profile_Remove
+@ stub ADL_ApplicationProfiles_PropertyType_Get
+@ stub ADL_ApplicationProfiles_Release_Get
+@ stub ADL_ApplicationProfiles_RemoveApplication
+@ stub ADL_ApplicationProfiles_StatusInfo_Get
+@ stub ADL_ApplicationProfiles_System_Reload
+@ stub ADL_ApplicationProfiles_User_Load
+@ stub ADL_ApplicationProfiles_User_Unload
+@ stub ADL_Audio_CurrentSampleRate_Get
+@ stub ADL_CDS_UnsafeMode_Set
+@ stub ADL_CV_DongleSettings_Get
+@ stub ADL_CV_DongleSettings_Reset
+@ stub ADL_CV_DongleSettings_Set
+@ stub ADL_DFP_AllowOnlyCETimings_Get
+@ stub ADL_DFP_AllowOnlyCETimings_Set
+@ stub ADL_DFP_BaseAudioSupport_Get
+@ stub ADL_DFP_GPUScalingEnable_Get
+@ stub ADL_DFP_GPUScalingEnable_Set
+@ stub ADL_DFP_HDMISupport_Get
+@ stub ADL_DFP_MVPUAnalogSupport_Get
+@ stub ADL_DFP_PixelFormat_Caps
+@ stub ADL_DFP_PixelFormat_Get
+@ stub ADL_DFP_PixelFormat_Set
+@ stub ADL_DisplayScaling_Set
+@ stub ADL_Display_AdapterID_Get
+@ stub ADL_Display_AdjustCaps_Get
+@ stub ADL_Display_AdjustmentCoherent_Get
+@ stub ADL_Display_AdjustmentCoherent_Set
+@ stub ADL_Display_AudioMappingInfo_Get
+@ stub ADL_Display_AvivoColor_Get
+@ stub ADL_Display_AvivoCurrentColor_Set
+@ stub ADL_Display_AvivoDefaultColor_Set
+@ stub ADL_Display_BackLight_Get
+@ stub ADL_Display_BackLight_Set
+@ stub ADL_Display_BezelOffsetSteppingSize_Get
+@ stub ADL_Display_BezelOffset_Set
+@ stub ADL_Display_BezelSupported_Validate
+@ stub ADL_Display_Capabilities_Get
+@ stub ADL_Display_ColorCaps_Get
+@ stub ADL_Display_ColorDepth_Get
+@ stub ADL_Display_ColorDepth_Set
+@ stub ADL_Display_ColorTemperatureSource_Get
+@ stub ADL_Display_ColorTemperatureSource_Set
+@ stub ADL_Display_Color_Get
+@ stub ADL_Display_Color_Set
+@ stub ADL_Display_ConnectedDisplays_Get
+@ stub ADL_Display_ContainerID_Get
+@ stub ADL_Display_ControllerOverlayAdjustmentCaps_Get
+@ stub ADL_Display_ControllerOverlayAdjustmentData_Get
+@ stub ADL_Display_ControllerOverlayAdjustmentData_Set
+@ stub ADL_Display_CurrentPixelClock_Get
+@ stub ADL_Display_CustomizedModeListNum_Get
+@ stub ADL_Display_CustomizedModeList_Get
+@ stub ADL_Display_CustomizedMode_Add
+@ stub ADL_Display_CustomizedMode_Delete
+@ stub ADL_Display_CustomizedMode_Validate
+@ stub ADL_Display_DCE_Get
+@ stub ADL_Display_DCE_Set
+@ stub ADL_Display_DDCBlockAccess_Get
+@ stub ADL_Display_DDCInfo2_Get
+@ stub ADL_Display_DDCInfo_Get
+@ stub ADL_Display_Deflicker_Get
+@ stub ADL_Display_Deflicker_Set
+@ stub ADL_Display_DeviceConfig_Get
+@ stub ADL_Display_DisplayContent_Cap
+@ stub ADL_Display_DisplayContent_Get
+@ stub ADL_Display_DisplayContent_Set
+@ stdcall ADL_Display_DisplayInfo_Get(long long ptr long)
+@ stdcall ADL_Display_DisplayMapConfig_Get(long ptr ptr ptr ptr long)
+@ stub ADL_Display_DisplayMapConfig_PossibleAddAndRemove
+@ stub ADL_Display_DisplayMapConfig_Set
+@ stub ADL_Display_DisplayMapConfig_Validate
+@ stub ADL_Display_DitherState_Get
+@ stub ADL_Display_DitherState_Set
+@ stub ADL_Display_Downscaling_Caps
+@ stub ADL_Display_DpMstInfo_Get
+@ stub ADL_Display_EdidData_Get
+@ stub ADL_Display_EdidData_Set
+@ stub ADL_Display_EnumDisplays_Get
+@ stub ADL_Display_FilterSVideo_Get
+@ stub ADL_Display_FilterSVideo_Set
+@ stub ADL_Display_ForcibleDisplay_Get
+@ stub ADL_Display_ForcibleDisplay_Set
+@ stub ADL_Display_FormatsOverride_Get
+@ stub ADL_Display_FormatsOverride_Set
+@ stub ADL_Display_FreeSyncState_Get
+@ stub ADL_Display_FreeSyncState_Set
+@ stub ADL_Display_FreeSync_Cap
+@ stub ADL_Display_GamutMapping_Get
+@ stub ADL_Display_GamutMapping_Reset
+@ stub ADL_Display_GamutMapping_Set
+@ stub ADL_Display_Gamut_Caps
+@ stub ADL_Display_Gamut_Get
+@ stub ADL_Display_Gamut_Set
+@ stub ADL_Display_ImageExpansion_Get
+@ stub ADL_Display_ImageExpansion_Set
+@ stub ADL_Display_InfoPacket_Get
+@ stub ADL_Display_InfoPacket_Set
+@ stub ADL_Display_LCDRefreshRateCapability_Get
+@ stub ADL_Display_LCDRefreshRateOptions_Get
+@ stub ADL_Display_LCDRefreshRateOptions_Set
+@ stub ADL_Display_LCDRefreshRate_Get
+@ stub ADL_Display_LCDRefreshRate_Set
+@ stub ADL_Display_Limits_Get
+@ stub ADL_Display_MVPUCaps_Get
+@ stub ADL_Display_MVPUStatus_Get
+@ stub ADL_Display_ModeTimingOverrideInfo_Get
+@ stub ADL_Display_ModeTimingOverrideListX2_Get
+@ stub ADL_Display_ModeTimingOverrideList_Get
+@ stub ADL_Display_ModeTimingOverrideX2_Get
+@ stub ADL_Display_ModeTimingOverride_Delete
+@ stub ADL_Display_ModeTimingOverride_Get
+@ stub ADL_Display_ModeTimingOverride_Set
+@ stub ADL_Display_Modes_Get
+@ stub ADL_Display_Modes_Set
+@ stub ADL_Display_MonitorPowerState_Set
+@ stub ADL_Display_NativeAUXChannel_Access
+@ stub ADL_Display_NeedWorkaroundFor5Clone_Get
+@ stub ADL_Display_NumberOfDisplays_Get
+@ stub ADL_Display_ODClockConfig_Set
+@ stub ADL_Display_ODClockInfo_Get
+@ stub ADL_Display_Overlap_Set
+@ stub ADL_Display_Overscan_Get
+@ stub ADL_Display_Overscan_Set
+@ stub ADL_Display_PixelClockAllowableRange_Set
+@ stub ADL_Display_PixelClockCaps_Get
+@ stub ADL_Display_PixelFormat_Get
+@ stub ADL_Display_PixelFormat_Set
+@ stub ADL_Display_Position_Get
+@ stub ADL_Display_Position_Set
+@ stub ADL_Display_PossibleMapping_Get
+@ stub ADL_Display_PossibleMode_Get
+@ stub ADL_Display_PowerXpressActiveGPU_Get
+@ stub ADL_Display_PowerXpressActiveGPU_Set
+@ stub ADL_Display_PowerXpressActvieGPUR2_Get
+@ stub ADL_Display_PowerXpressVersion_Get
+@ stub ADL_Display_PowerXpress_AutoSwitchConfig_Get
+@ stub ADL_Display_PowerXpress_AutoSwitchConfig_Set
+@ stub ADL_Display_PreservedAspectRatio_Get
+@ stub ADL_Display_PreservedAspectRatio_Set
+@ stub ADL_Display_Property_Get
+@ stub ADL_Display_Property_Set
+@ stub ADL_Display_RcDisplayAdjustment
+@ stub ADL_Display_ReGammaCoefficients_Get
+@ stub ADL_Display_ReGammaCoefficients_Set
+@ stub ADL_Display_ReducedBlanking_Get
+@ stub ADL_Display_ReducedBlanking_Set
+@ stub ADL_Display_RegammaR1_Get
+@ stub ADL_Display_RegammaR1_Set
+@ stub ADL_Display_Regamma_Get
+@ stub ADL_Display_Regamma_Set
+@ stub ADL_Display_SLSGrid_Caps
+@ stub ADL_Display_SLSMapConfigX2_Get
+@ stub ADL_Display_SLSMapConfig_Create
+@ stub ADL_Display_SLSMapConfig_Delete
+@ stub ADL_Display_SLSMapConfig_Get
+@ stub ADL_Display_SLSMapConfig_Rearrange
+@ stub ADL_Display_SLSMapConfig_SetState
+@ stub ADL_Display_SLSMapIndexList_Get
+@ stub ADL_Display_SLSMapIndex_Get
+@ stub ADL_Display_SLSMiddleMode_Get
+@ stub ADL_Display_SLSMiddleMode_Set
+@ stub ADL_Display_SLSRecords_Get
+@ stub ADL_Display_Sharpness_Caps
+@ stub ADL_Display_Sharpness_Get
+@ stub ADL_Display_Sharpness_Info_Get
+@ stub ADL_Display_Sharpness_Set
+@ stub ADL_Display_Size_Get
+@ stub ADL_Display_Size_Set
+@ stub ADL_Display_SourceContentAttribute_Get
+@ stub ADL_Display_SourceContentAttribute_Set
+@ stub ADL_Display_SplitDisplay_Caps
+@ stub ADL_Display_SplitDisplay_Get
+@ stub ADL_Display_SplitDisplay_RestoreDesktopConfiguration
+@ stub ADL_Display_SplitDisplay_Set
+@ stub ADL_Display_SupportedColorDepth_Get
+@ stub ADL_Display_SupportedPixelFormat_Get
+@ stub ADL_Display_SwitchingCapability_Get
+@ stub ADL_Display_TVCaps_Get
+@ stub ADL_Display_TargetTiming_Get
+@ stub ADL_Display_UnderScan_Auto_Get
+@ stub ADL_Display_UnderScan_Auto_Set
+@ stub ADL_Display_Underscan_Get
+@ stub ADL_Display_Underscan_Set
+@ stub ADL_Display_Vector_Get
+@ stub ADL_Display_ViewPort_Cap
+@ stub ADL_Display_ViewPort_Get
+@ stub ADL_Display_ViewPort_Set
+@ stub ADL_Display_WriteAndReadI2C
+@ stub ADL_Display_WriteAndReadI2CLargePayload
+@ stub ADL_Display_WriteAndReadI2CRev_Get
+@ stub ADL_Flush_Driver_Data
+@ stdcall ADL_Graphics_Platform_Get(ptr)
+@ stdcall ADL_Graphics_Versions_Get(ptr)
+@ stub ADL_MMD_FeatureList_Get
+@ stub ADL_MMD_FeatureValuesX2_Get
+@ stub ADL_MMD_FeatureValuesX2_Set
+@ stub ADL_MMD_FeatureValues_Get
+@ stub ADL_MMD_FeatureValues_Set
+@ stub ADL_MMD_FeaturesX2_Caps
+@ stub ADL_MMD_Features_Caps
+@ stub ADL_MMD_VideoAdjustInfo_Get
+@ stub ADL_MMD_VideoAdjustInfo_Set
+@ stub ADL_MMD_VideoColor_Caps
+@ stub ADL_MMD_VideoColor_Get
+@ stub ADL_MMD_VideoColor_Set
+@ stub ADL_MMD_Video_Caps
+@ stub ADL_Main_ControlX2_Create
+@ stdcall ADL_Main_Control_Create(ptr long)
+@ stdcall ADL_Main_Control_Destroy()
+@ stub ADL_Main_Control_GetProcAddress
+@ stub ADL_Main_Control_IsFunctionValid
+@ stub ADL_Main_Control_Refresh
+@ stub ADL_Main_LogDebug_Set
+@ stub ADL_Main_LogError_Set
+@ stub ADL_Overdrive5_CurrentActivity_Get
+@ stub ADL_Overdrive5_FanSpeedInfo_Get
+@ stub ADL_Overdrive5_FanSpeedToDefault_Set
+@ stub ADL_Overdrive5_FanSpeed_Get
+@ stub ADL_Overdrive5_FanSpeed_Set
+@ stub ADL_Overdrive5_ODParameters_Get
+@ stub ADL_Overdrive5_ODPerformanceLevels_Get
+@ stub ADL_Overdrive5_ODPerformanceLevels_Set
+@ stub ADL_Overdrive5_PowerControlAbsValue_Caps
+@ stub ADL_Overdrive5_PowerControlAbsValue_Get
+@ stub ADL_Overdrive5_PowerControlAbsValue_Set
+@ stub ADL_Overdrive5_PowerControlInfo_Get
+@ stub ADL_Overdrive5_PowerControl_Caps
+@ stub ADL_Overdrive5_PowerControl_Get
+@ stub ADL_Overdrive5_PowerControl_Set
+@ stub ADL_Overdrive5_Temperature_Get
+@ stub ADL_Overdrive5_ThermalDevices_Enum
+@ stub ADL_Overdrive6_AdvancedFan_Caps
+@ stub ADL_Overdrive6_CapabilitiesEx_Get
+@ stub ADL_Overdrive6_Capabilities_Get
+@ stub ADL_Overdrive6_CurrentStatus_Get
+@ stub ADL_Overdrive6_FanPWMLimitData_Get
+@ stub ADL_Overdrive6_FanPWMLimitData_Set
+@ stub ADL_Overdrive6_FanPWMLimitRangeInfo_Get
+@ stub ADL_Overdrive6_FanSpeed_Get
+@ stub ADL_Overdrive6_FanSpeed_Reset
+@ stub ADL_Overdrive6_FanSpeed_Set
+@ stub ADL_Overdrive6_FuzzyController_Caps
+@ stub ADL_Overdrive6_MaxClockAdjust_Get
+@ stub ADL_Overdrive6_PowerControlInfo_Get
+@ stub ADL_Overdrive6_PowerControl_Caps
+@ stub ADL_Overdrive6_PowerControl_Get
+@ stub ADL_Overdrive6_PowerControl_Set
+@ stub ADL_Overdrive6_StateEx_Get
+@ stub ADL_Overdrive6_StateEx_Set
+@ stub ADL_Overdrive6_StateInfo_Get
+@ stub ADL_Overdrive6_State_Reset
+@ stub ADL_Overdrive6_State_Set
+@ stub ADL_Overdrive6_TargetTemperatureData_Get
+@ stub ADL_Overdrive6_TargetTemperatureData_Set
+@ stub ADL_Overdrive6_TargetTemperatureRangeInfo_Get
+@ stub ADL_Overdrive6_Temperature_Get
+@ stub ADL_Overdrive6_ThermalController_Caps
+@ stub ADL_Overdrive6_ThermalLimitUnlock_Get
+@ stub ADL_Overdrive6_ThermalLimitUnlock_Set
+@ stub ADL_Overdrive6_VoltageControlInfo_Get
+@ stub ADL_Overdrive6_VoltageControl_Get
+@ stub ADL_Overdrive6_VoltageControl_Set
+@ stub ADL_Overdrive_Caps
+@ stub ADL_PowerXpress_AncillaryDevices_Get
+@ stub ADL_PowerXpress_Config_Caps
+@ stub ADL_PowerXpress_ExtendedBatteryMode_Caps
+@ stub ADL_PowerXpress_ExtendedBatteryMode_Get
+@ stub ADL_PowerXpress_ExtendedBatteryMode_Set
+@ stub ADL_PowerXpress_LongIdleDetect_Get
+@ stub ADL_PowerXpress_LongIdleDetect_Set
+@ stub ADL_PowerXpress_PowerControlMode_Get
+@ stub ADL_PowerXpress_PowerControlMode_Set
+@ stub ADL_PowerXpress_Scheme_Get
+@ stub ADL_PowerXpress_Scheme_Set
+@ stub ADL_Remap
+@ stub ADL_RemoteDisplay_Destroy
+@ stub ADL_RemoteDisplay_Display_Acquire
+@ stub ADL_RemoteDisplay_Display_Release
+@ stub ADL_RemoteDisplay_Display_Release_All
+@ stub ADL_RemoteDisplay_Hdcp20_Create
+@ stub ADL_RemoteDisplay_Hdcp20_Destroy
+@ stub ADL_RemoteDisplay_Hdcp20_Notify
+@ stub ADL_RemoteDisplay_Hdcp20_Process
+@ stub ADL_RemoteDisplay_IEPort_Set
+@ stub ADL_RemoteDisplay_Initialize
+@ stub ADL_RemoteDisplay_Nofitiation_Register
+@ stub ADL_RemoteDisplay_Notification_UnRegister
+@ stub ADL_RemoteDisplay_Support_Caps
+@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_InUse_Get
+@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_Info_Get
+@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_RadioState_Get
+@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Change
+@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Get
+@ stub ADL_RemoteDisplay_WFDDeviceInfo_Get
+@ stub ADL_RemoteDisplay_WFDDeviceName_Change
+@ stub ADL_RemoteDisplay_WFDDevice_StatusInfo_Get
+@ stub ADL_RemoteDisplay_WFDDiscover_Start
+@ stub ADL_RemoteDisplay_WFDDiscover_Stop
+@ stub ADL_RemoteDisplay_WFDLink_Connect
+@ stub ADL_RemoteDisplay_WFDLink_Creation_Accept
+@ stub ADL_RemoteDisplay_WFDLink_Disconnect
+@ stub ADL_RemoteDisplay_WFDLink_WPS_Process
+@ stub ADL_RemoteDisplay_WFDWDSPSettings_Set
+@ stub ADL_RemoteDisplay_WirelessDisplayEnableDisable_Commit
+@ stub ADL_ScreenPoint_AudioMappingInfo_Get
+@ stub ADL_Stereo3D_2DPackedFormat_Set
+@ stub ADL_Stereo3D_3DCursorOffset_Get
+@ stub ADL_Stereo3D_3DCursorOffset_Set
+@ stub ADL_Stereo3D_CurrentFormat_Get
+@ stub ADL_Stereo3D_Info_Get
+@ stub ADL_Stereo3D_Modes_Get
+@ stub ADL_TV_Standard_Get
+@ stub ADL_TV_Standard_Set
+@ stub ADL_Win_IsHybridAI
+@ stub ADL_Workstation_8BitGrayscale_Get
+@ stub ADL_Workstation_8BitGrayscale_Set
+@ stub ADL_Workstation_AdapterNumOfGLSyncConnectors_Get
+@ stub ADL_Workstation_Caps
+@ stub ADL_Workstation_DeepBitDepthX2_Get
+@ stub ADL_Workstation_DeepBitDepthX2_Set
+@ stub ADL_Workstation_DeepBitDepth_Get
+@ stub ADL_Workstation_DeepBitDepth_Set
+@ stub ADL_Workstation_DisplayGLSyncMode_Get
+@ stub ADL_Workstation_DisplayGLSyncMode_Set
+@ stub ADL_Workstation_DisplayGenlockCapable_Get
+@ stub ADL_Workstation_ECCData_Get
+@ stub ADL_Workstation_ECCX2_Get
+@ stub ADL_Workstation_ECC_Caps
+@ stub ADL_Workstation_ECC_Get
+@ stub ADL_Workstation_ECC_Set
+@ stub ADL_Workstation_GLSyncCounters_Get
+@ stub ADL_Workstation_GLSyncGenlockConfiguration_Get
+@ stub ADL_Workstation_GLSyncGenlockConfiguration_Set
+@ stub ADL_Workstation_GLSyncModuleDetect_Get
+@ stub ADL_Workstation_GLSyncModuleInfo_Get
+@ stub ADL_Workstation_GLSyncPortState_Get
+@ stub ADL_Workstation_GLSyncPortState_Set
+@ stub ADL_Workstation_GLSyncSupportedTopology_Get
+@ stub ADL_Workstation_GlobalEDIDPersistence_Get
+@ stub ADL_Workstation_GlobalEDIDPersistence_Set
+@ stub ADL_Workstation_LoadBalancing_Caps
+@ stub ADL_Workstation_LoadBalancing_Get
+@ stub ADL_Workstation_LoadBalancing_Set
+@ stub ADL_Workstation_RAS_Get_Error_Counts
+@ stub ADL_Workstation_RAS_Get_Features
+@ stub ADL_Workstation_RAS_Reset_Error_Counts
+@ stub ADL_Workstation_RAS_Set_Features
+@ stub ADL_Workstation_SDISegmentList_Get
+@ stub ADL_Workstation_SDI_Caps
+@ stub ADL_Workstation_SDI_Get
+@ stub ADL_Workstation_SDI_Set
+@ stub ADL_Workstation_Stereo_Get
+@ stub ADL_Workstation_Stereo_Set
+@ stub ADL_Workstation_UnsupportedDisplayModes_Enable
+@ stub AmdPowerXpressRequestHighPerformance
+@ stub Desktop_Detach
+@ stub Send
+@ stub SendX2
diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c
new file mode 100644
index 00000000000..21dfbe71096
--- /dev/null
+++ wine/dlls/atiadlxx/atiadlxx_main.c
@@ -0,0 +1,493 @@
+/* Headers: https://github.com/GPUOpen-LibrariesAndSDKs/display-library */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define COBJMACROS
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "objbase.h"
+#include "initguid.h"
+#include "wine/debug.h"
+
+#include "dxgi.h"
+
+#define MAX_GPUS 64
+#define VENDOR_AMD 0x1002
+
+#define ADL_OK 0
+#define ADL_ERR -1
+#define ADL_ERR_INVALID_PARAM -3
+#define ADL_ERR_INVALID_ADL_IDX -5
+#define ADL_ERR_NOT_SUPPORTED -8
+#define ADL_ERR_NULL_POINTER -9
+
+#define ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED 0x00000001
+#define ADL_DISPLAY_DISPLAYINFO_DISPLAYMAPPED 0x00000002
+#define ADL_DISPLAY_DISPLAYINFO_MASK 0x31fff
+
+#define ADL_ASIC_DISCRETE (1 << 0)
+#define ADL_ASIC_MASK 0xAF
+
+enum ADLPlatForm
+{
+ GRAPHICS_PLATFORM_DESKTOP = 0,
+ GRAPHICS_PLATFORM_MOBILE = 1
+};
+#define GRAPHICS_PLATFORM_UNKNOWN -1
+
+
+static IDXGIFactory *dxgi_factory;
+
+WINE_DEFAULT_DEBUG_CHANNEL(atiadlxx);
+
+BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
+{
+ TRACE("(%p, %u, %p)\n", instance, reason, reserved);
+
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(instance);
+ break;
+ }
+
+ return TRUE;
+}
+
+typedef void *(CALLBACK *ADL_MAIN_MALLOC_CALLBACK)(int);
+typedef void *ADL_CONTEXT_HANDLE;
+
+ADL_MAIN_MALLOC_CALLBACK adl_malloc;
+#define ADL_MAX_PATH 256
+
+typedef struct ADLVersionsInfo
+{
+ char strDriverVer[ADL_MAX_PATH];
+ char strCatalystVersion[ADL_MAX_PATH];
+ char strCatalystWebLink[ADL_MAX_PATH];
+} ADLVersionsInfo, *LPADLVersionsInfo;
+
+typedef struct ADLVersionsInfoX2
+{
+ char strDriverVer[ADL_MAX_PATH];
+ char strCatalystVersion[ADL_MAX_PATH];
+ char strCrimsonVersion[ADL_MAX_PATH];
+ char strCatalystWebLink[ADL_MAX_PATH];
+} ADLVersionsInfoX2, *LPADLVersionsInfoX2;
+
+typedef struct ADLAdapterInfo {
+ int iSize;
+ int iAdapterIndex;
+ char strUDID[ADL_MAX_PATH];
+ int iBusNumber;
+ int iDeviceNumber;
+ int iFunctionNumber;
+ int iVendorID;
+ char strAdapterName[ADL_MAX_PATH];
+ char strDisplayName[ADL_MAX_PATH];
+ int iPresent;
+ int iExist;
+ char strDriverPath[ADL_MAX_PATH];
+ char strDriverPathExt[ADL_MAX_PATH];
+ char strPNPString[ADL_MAX_PATH];
+ int iOSDisplayIndex;
+} ADLAdapterInfo, *LPADLAdapterInfo;
+
+typedef struct ADLDisplayID
+{
+ int iDisplayLogicalIndex;
+ int iDisplayPhysicalIndex;
+ int iDisplayLogicalAdapterIndex;
+ int iDisplayPhysicalAdapterIndex;
+} ADLDisplayID, *LPADLDisplayID;
+
+typedef struct ADLDisplayInfo
+{
+ ADLDisplayID displayID;
+ int iDisplayControllerIndex;
+ char strDisplayName[ADL_MAX_PATH];
+ char strDisplayManufacturerName[ADL_MAX_PATH];
+ int iDisplayType;
+ int iDisplayOutputType;
+ int iDisplayConnector;
+ int iDisplayInfoMask;
+ int iDisplayInfoValue;
+} ADLDisplayInfo, *LPADLDisplayInfo;
+
+typedef struct ADLCrossfireComb
+{
+ int iNumLinkAdapter;
+ int iAdaptLink[3];
+} ADLCrossfireComb;
+
+typedef struct ADLCrossfireInfo
+{
+ int iErrorCode;
+ int iState;
+ int iSupported;
+} ADLCrossfireInfo;
+
+typedef struct ADLMemoryInfo
+{
+ long long iMemorySize;
+ char strMemoryType[ADL_MAX_PATH];
+ long long iMemoryBandwidth;
+} ADLMemoryInfo, *LPADLMemoryInfo;
+
+typedef struct ADLDisplayTarget
+{
+ ADLDisplayID displayID;
+ int iDisplayMapIndex;
+ int iDisplayTargetMask;
+ int iDisplayTargetValue;
+} ADLDisplayTarget, *LPADLDisplayTarget;
+
+typedef struct ADLMode
+{
+ int iAdapterIndex;
+ ADLDisplayID displayID;
+ int iXPos;
+ int iYPos;
+ int iXRes;
+ int iYRes;
+ int iColourDepth;
+ float fRefreshRate;
+ int iOrientation;
+ int iModeFlag;
+ int iModeMask;
+ int iModeValue;
+} ADLMode, *LPADLMode;
+
+typedef struct ADLDisplayMap
+{
+ int iDisplayMapIndex;
+ ADLMode displayMode;
+ int iNumDisplayTarget;
+ int iFirstDisplayTargetArrayIndex;
+ int iDisplayMapMask;
+ int iDisplayMapValue;
+} ADLDisplayMap, *LPADLDisplayMap;
+
+static const ADLVersionsInfo version = {
+ "22.20.19.16-221003a-384125E-AMD-Software-Adrenalin-Edition",
+ "",
+ "http://support.amd.com/drivers/xml/driver_09_us.xml",
+};
+
+static const ADLVersionsInfoX2 version2 = {
+ "22.20.19.16-221003a-384125E-AMD-Software-Adrenalin-Edition",
+ "",
+ "22.10.1",
+ "http://support.amd.com/drivers/xml/driver_09_us.xml",
+};
+
+int WINAPI ADL2_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg, ADL_CONTEXT_HANDLE *ptr)
+{
+ FIXME("cb %p, arg %d, ptr %p stub!\n", cb, arg, ptr);
+ return ADL_OK;
+}
+
+int WINAPI ADL_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg)
+{
+ FIXME("cb %p, arg %d stub!\n", cb, arg);
+ adl_malloc = cb;
+
+
+ if (SUCCEEDED(CreateDXGIFactory(&IID_IDXGIFactory, (void**) &dxgi_factory)))
+ return ADL_OK;
+ else
+ return ADL_ERR;
+}
+
+int WINAPI ADL_Main_Control_Destroy(void)
+{
+ FIXME("stub!\n");
+
+ if (dxgi_factory != NULL)
+ IUnknown_Release(dxgi_factory);
+
+ return ADL_OK;
+}
+
+int WINAPI ADL2_Adapter_NumberOfAdapters_Get(ADL_CONTEXT_HANDLE *ptr, int *count)
+{
+ FIXME("ptr %p, count %p stub!\n", ptr, count);
+
+ *count = 0;
+
+ return ADL_OK;
+}
+
+int WINAPI ADL2_Graphics_VersionsX2_Get(ADL_CONTEXT_HANDLE *ptr, ADLVersionsInfoX2 *ver)
+{
+ FIXME("ptr %p, ver %p stub!\n", ptr, ver);
+ memcpy(ver, &version2, sizeof(version2));
+ return ADL_OK;
+}
+
+int WINAPI ADL_Graphics_Versions_Get(ADLVersionsInfo *ver)
+{
+ FIXME("ver %p stub!\n", ver);
+ memcpy(ver, &version, sizeof(version));
+ return ADL_OK;
+}
+
+int WINAPI ADL_Adapter_NumberOfAdapters_Get(int *count)
+{
+ IDXGIAdapter *adapter;
+
+ FIXME("count %p stub!\n", count);
+
+ *count = 0;
+ while (SUCCEEDED(IDXGIFactory_EnumAdapters(dxgi_factory, *count, &adapter)))
+ {
+ (*count)++;
+ IUnknown_Release(adapter);
+ }
+
+ TRACE("*count = %d\n", *count);
+ return ADL_OK;
+}
+
+static int get_adapter_desc(int adapter_index, DXGI_ADAPTER_DESC *desc)
+{
+ IDXGIAdapter *adapter;
+ HRESULT hr;
+
+ if (FAILED(IDXGIFactory_EnumAdapters(dxgi_factory, adapter_index, &adapter)))
+ return ADL_ERR;
+
+ hr = IDXGIAdapter_GetDesc(adapter, desc);
+
+ IUnknown_Release(adapter);
+
+ return SUCCEEDED(hr) ? ADL_OK : ADL_ERR;
+}
+
+/* yep, seriously */
+static int convert_vendor_id(int id)
+{
+ char str[16];
+ snprintf(str, ARRAY_SIZE(str), "%x", id);
+ return atoi(str);
+}
+
+int WINAPI ADL_Adapter_AdapterInfo_Get(ADLAdapterInfo *adapters, int input_size)
+{
+ int count, i;
+ DXGI_ADAPTER_DESC adapter_desc;
+
+ FIXME("adapters %p, input_size %d, stub!\n", adapters, input_size);
+
+ ADL_Adapter_NumberOfAdapters_Get(&count);
+
+ if (!adapters) return ADL_ERR_INVALID_PARAM;
+ if (input_size != count * sizeof(ADLAdapterInfo)) return ADL_ERR_INVALID_PARAM;
+
+ memset(adapters, 0, input_size);
+
+ for (i = 0; i < count; i++)
+ {
+ adapters[i].iSize = sizeof(ADLAdapterInfo);
+ adapters[i].iAdapterIndex = i;
+
+ if (get_adapter_desc(i, &adapter_desc) != ADL_OK)
+ return ADL_ERR;
+
+ adapters[i].iVendorID = convert_vendor_id(adapter_desc.VendorId);
+ }
+
+ return ADL_OK;
+}
+
+int WINAPI ADL_Display_DisplayInfo_Get(int adapter_index, int *num_displays, ADLDisplayInfo **info, int force_detect)
+{
+ IDXGIAdapter *adapter;
+ IDXGIOutput *output;
+ int i;
+
+ FIXME("adapter %d, num_displays %p, info %p stub!\n", adapter_index, num_displays, info);
+
+ if (info == NULL || num_displays == NULL) return ADL_ERR_NULL_POINTER;
+
+ if (FAILED(IDXGIFactory_EnumAdapters(dxgi_factory, adapter_index, &adapter)))
+ return ADL_ERR_INVALID_PARAM;
+
+ *num_displays = 0;
+
+ while (SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, *num_displays, &output)))
+ {
+ (*num_displays)++;
+ IUnknown_Release(output);
+ }
+
+ IUnknown_Release(adapter);
+
+ if (*num_displays == 0)
+ return ADL_OK;
+
+ *info = adl_malloc(*num_displays * sizeof(**info));
+ memset(*info, 0, *num_displays * sizeof(**info));
+
+ for (i = 0; i < *num_displays; i++)
+ {
+ (*info)[i].displayID.iDisplayLogicalIndex = i;
+ (*info)[i].iDisplayInfoValue = ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED | ADL_DISPLAY_DISPLAYINFO_DISPLAYMAPPED;
+ (*info)[i].iDisplayInfoMask = (*info)[i].iDisplayInfoValue;
+ }
+
+ return ADL_OK;
+}
+
+int WINAPI ADL_Adapter_Crossfire_Caps(int adapter_index, int *preffered, int *num_comb, ADLCrossfireComb** comb)
+{
+ FIXME("adapter %d, preffered %p, num_comb %p, comb %p stub!\n", adapter_index, preffered, num_comb, comb);
+ return ADL_ERR;
+}
+
+int WINAPI ADL_Adapter_Crossfire_Get(int adapter_index, ADLCrossfireComb *comb, ADLCrossfireInfo *info)
+{
+ FIXME("adapter %d, comb %p, info %p, stub!\n", adapter_index, comb, info);
+ return ADL_ERR;
+}
+
+int WINAPI ADL_Adapter_ASICFamilyType_Get(int adapter_index, int *asic_type, int *valids)
+{
+ DXGI_ADAPTER_DESC adapter_desc;
+
+ FIXME("adapter %d, asic_type %p, valids %p, stub!\n", adapter_index, asic_type, valids);
+
+ if (asic_type == NULL || valids == NULL)
+ return ADL_ERR_NULL_POINTER;
+
+ if (get_adapter_desc(adapter_index, &adapter_desc) != ADL_OK)
+ return ADL_ERR_INVALID_ADL_IDX;
+
+ if (adapter_desc.VendorId != VENDOR_AMD)
+ return ADL_ERR_NOT_SUPPORTED;
+
+ *asic_type = ADL_ASIC_DISCRETE;
+ *valids = ADL_ASIC_MASK;
+
+ return ADL_OK;
+}
+
+static int get_max_clock(const char *clock, int default_value)
+{
+ char path[MAX_PATH], line[256];
+ FILE *file;
+ int drm_card, value = 0;
+
+ for (drm_card = 0; drm_card < MAX_GPUS; drm_card++)
+ {
+ sprintf(path, "/sys/class/drm/card%d/device/pp_dpm_%s", drm_card, clock);
+ file = fopen(path, "r");
+
+ if (file == NULL)
+ continue;
+
+ while (fgets(line, sizeof(line), file) != NULL)
+ {
+ char *number;
+
+ number = strchr(line, ' ');
+ if (number == NULL)
+ {
+ WARN("pp_dpm_%s file has unexpected format\n", clock);
+ break;
+ }
+
+ number++;
+ value = max(strtol(number, NULL, 0), value);
+ }
+ }
+
+ if (value != 0)
+ return value;
+
+ return default_value;
+}
+
+/* documented in the "Linux Specific APIs" section, present and used on Windows */
+/* the name and documentation suggests that this returns current freqs, but it's actually max */
+int WINAPI ADL_Adapter_ObservedClockInfo_Get(int adapter_index, int *core_clock, int *memory_clock)
+{
+ DXGI_ADAPTER_DESC adapter_desc;
+
+ FIXME("adapter %d, core_clock %p, memory_clock %p, stub!\n", adapter_index, core_clock, memory_clock);
+
+ if (core_clock == NULL || memory_clock == NULL) return ADL_ERR;
+ if (get_adapter_desc(adapter_index, &adapter_desc) != ADL_OK) return ADL_ERR;
+ if (adapter_desc.VendorId != VENDOR_AMD) return ADL_ERR_INVALID_ADL_IDX;
+
+ /* default values based on RX580 */
+ *core_clock = get_max_clock("sclk", 1350);
+ *memory_clock = get_max_clock("mclk", 2000);
+
+ TRACE("*core_clock: %i, *memory_clock %i\n", *core_clock, *memory_clock);
+
+ return ADL_OK;
+}
+
+/* documented in the "Linux Specific APIs" section, present and used on Windows */
+int WINAPI ADL_Adapter_MemoryInfo_Get(int adapter_index, ADLMemoryInfo *mem_info)
+{
+ DXGI_ADAPTER_DESC adapter_desc;
+
+ FIXME("adapter %d, mem_info %p stub!\n", adapter_index, mem_info);
+
+ if (mem_info == NULL) return ADL_ERR_NULL_POINTER;
+ if (get_adapter_desc(adapter_index, &adapter_desc) != ADL_OK) return ADL_ERR_INVALID_ADL_IDX;
+ if (adapter_desc.VendorId != VENDOR_AMD) return ADL_ERR;
+
+ mem_info->iMemorySize = adapter_desc.DedicatedVideoMemory;
+ mem_info->iMemoryBandwidth = 256000; /* not exposed on Linux, probably needs a lookup table */
+
+ TRACE("iMemoryBandwidth %s, iMemorySize %s\n",
+ wine_dbgstr_longlong(mem_info->iMemoryBandwidth),
+ wine_dbgstr_longlong(mem_info->iMemorySize));
+ return ADL_OK;
+}
+
+int WINAPI ADL_Graphics_Platform_Get(int *platform)
+{
+ DXGI_ADAPTER_DESC adapter_desc;
+ int count, i;
+
+ FIXME("platform %p, stub!\n", platform);
+
+ *platform = GRAPHICS_PLATFORM_UNKNOWN;
+
+ ADL_Adapter_NumberOfAdapters_Get(&count);
+
+ for (i = 0; i < count; i ++)
+ {
+ if (get_adapter_desc(i, &adapter_desc) != ADL_OK)
+ continue;
+
+ if (adapter_desc.VendorId == VENDOR_AMD)
+ *platform = GRAPHICS_PLATFORM_DESKTOP;
+ }
+
+ /* NOTE: The real value can be obtained by doing:
+ * 1. ioctl(DRM_AMDGPU_INFO) with AMDGPU_INFO_DEV_INFO - dev_info.ids_flags & AMDGPU_IDS_FLAGS_FUSION
+ * 2. VkPhysicalDeviceType() if we ever want to use Vulkan directly
+ */
+
+ return ADL_OK;
+}
+
+
+int WINAPI ADL_Display_DisplayMapConfig_Get(int adapter_index, int *display_map_count, ADLDisplayMap **display_maps,
+ int *display_target_count, ADLDisplayTarget **display_targets, int options)
+{
+ FIXME("adapter_index %d, display_map_count %p, display_maps %p, "
+ "display_target_count %p, display_targets %p, options %d stub.\n",
+ adapter_index, display_map_count, display_maps, display_target_count,
+ display_targets, options);
+
+ return ADL_ERR;
+}
--
2.39.2 (Apple Git-144)
diff --git a/dlls/windows.gaming.input/Makefile.in b/dlls/windows.gaming.input/Makefile.in
index 1e0ce5c360c..3ec3dd0d864 100644
--- wine/dlls/windows.gaming.input/Makefile.in
+++ wine/dlls/windows.gaming.input/Makefile.in
@@ -2,13 +2,19 @@ MODULE = windows.gaming.input.dll
IMPORTS = combase uuid user32 dinput8 setupapi hid
C_SRCS = \
+ async.c \
+ condition_effect.c \
+ constant_effect.c \
controller.c \
event_handlers.c \
+ force_feedback.c \
gamepad.c \
main.c \
manager.c \
+ periodic_effect.c \
provider.c \
racing_wheel.c \
+ ramp_effect.c \
vector.c
IDL_SRCS = \
diff --git a/dlls/windows.gaming.input/async.c b/dlls/windows.gaming.input/async.c
new file mode 100644
index 00000000000..862886195ba
--- /dev/null
+++ wine/dlls/windows.gaming.input/async.c
@@ -0,0 +1,647 @@
+/* WinRT Windows.Gaming.Input implementation
+ *
+ * Copyright 2022 Bernhard Kölbl for CodeWeavers
+ * Copyright 2022 Rémi Bernon for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "private.h"
+#include "provider.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(input);
+
+#define Closed 4
+#define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0)
+
+struct async_info
+{
+ IWineAsyncInfoImpl IWineAsyncInfoImpl_iface;
+ IAsyncInfo IAsyncInfo_iface;
+ IInspectable *IInspectable_outer;
+ LONG ref;
+
+ async_operation_callback callback;
+ TP_WORK *async_run_work;
+ IUnknown *invoker;
+ IUnknown *param;
+
+ CRITICAL_SECTION cs;
+ IWineAsyncOperationCompletedHandler *handler;
+ PROPVARIANT result;
+ AsyncStatus status;
+ HRESULT hr;
+};
+
+static inline struct async_info *impl_from_IWineAsyncInfoImpl( IWineAsyncInfoImpl *iface )
+{
+ return CONTAINING_RECORD( iface, struct async_info, IWineAsyncInfoImpl_iface );
+}
+
+static HRESULT WINAPI async_impl_QueryInterface( IWineAsyncInfoImpl *iface, REFIID iid, void **out )
+{
+ struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IWineAsyncInfoImpl ))
+ {
+ IInspectable_AddRef( (*out = &impl->IWineAsyncInfoImpl_iface) );
+ return S_OK;
+ }
+
+ if (IsEqualGUID( iid, &IID_IAsyncInfo ))
+ {
+ IInspectable_AddRef( (*out = &impl->IAsyncInfo_iface) );
+ return S_OK;
+ }
+
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI async_impl_AddRef( IWineAsyncInfoImpl *iface )
+{
+ struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p, ref %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI async_impl_Release( IWineAsyncInfoImpl *iface )
+{
+ struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+ TRACE( "iface %p, ref %lu.\n", iface, ref );
+
+ if (!ref)
+ {
+ if (impl->handler && impl->handler != HANDLER_NOT_SET) IWineAsyncOperationCompletedHandler_Release( impl->handler );
+ IAsyncInfo_Close( &impl->IAsyncInfo_iface );
+ if (impl->param) IUnknown_Release( impl->param );
+ if (impl->invoker) IUnknown_Release( impl->invoker );
+ impl->cs.DebugInfo->Spare[0] = 0;
+ DeleteCriticalSection( &impl->cs );
+ free( impl );
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI async_impl_put_Completed( IWineAsyncInfoImpl *iface, IWineAsyncOperationCompletedHandler *handler )
+{
+ struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface );
+ HRESULT hr = S_OK;
+
+ TRACE( "iface %p, handler %p.\n", iface, handler );
+
+ EnterCriticalSection( &impl->cs );
+ if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL;
+ else if (impl->handler != HANDLER_NOT_SET) hr = E_ILLEGAL_DELEGATE_ASSIGNMENT;
+ else if ((impl->handler = handler))
+ {
+ IWineAsyncOperationCompletedHandler_AddRef( impl->handler );
+
+ if (impl->status > Started)
+ {
+ IInspectable *operation = impl->IInspectable_outer;
+ AsyncStatus status = impl->status;
+ impl->handler = NULL; /* Prevent concurrent invoke. */
+ LeaveCriticalSection( &impl->cs );
+
+ IWineAsyncOperationCompletedHandler_Invoke( handler, operation, status );
+ IWineAsyncOperationCompletedHandler_Release( handler );
+
+ return S_OK;
+ }
+ }
+ LeaveCriticalSection( &impl->cs );
+
+ return hr;
+}
+
+static HRESULT WINAPI async_impl_get_Completed( IWineAsyncInfoImpl *iface, IWineAsyncOperationCompletedHandler **handler )
+{
+ struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface );
+ HRESULT hr = S_OK;
+
+ TRACE( "iface %p, handler %p.\n", iface, handler );
+
+ EnterCriticalSection( &impl->cs );
+ if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL;
+ if (impl->handler == NULL || impl->handler == HANDLER_NOT_SET) *handler = NULL;
+ else IWineAsyncOperationCompletedHandler_AddRef( (*handler = impl->handler) );
+ LeaveCriticalSection( &impl->cs );
+
+ return hr;
+}
+
+static HRESULT WINAPI async_impl_get_Result( IWineAsyncInfoImpl *iface, PROPVARIANT *result )
+{
+ struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface );
+ HRESULT hr = E_ILLEGAL_METHOD_CALL;
+
+ TRACE( "iface %p, result %p.\n", iface, result );
+
+ EnterCriticalSection( &impl->cs );
+ if (impl->status == Completed || impl->status == Error)
+ {
+ PropVariantCopy( result, &impl->result );
+ hr = impl->hr;
+ }
+ LeaveCriticalSection( &impl->cs );
+
+ return hr;
+}
+
+static HRESULT WINAPI async_impl_Start( IWineAsyncInfoImpl *iface )
+{
+ struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface );
+
+ TRACE( "iface %p.\n", iface );
+
+ /* keep the async alive in the callback */
+ IInspectable_AddRef( impl->IInspectable_outer );
+ SubmitThreadpoolWork( impl->async_run_work );
+
+ return S_OK;
+}
+
+static const struct IWineAsyncInfoImplVtbl async_impl_vtbl =
+{
+ /* IUnknown methods */
+ async_impl_QueryInterface,
+ async_impl_AddRef,
+ async_impl_Release,
+ /* IWineAsyncInfoImpl */
+ async_impl_put_Completed,
+ async_impl_get_Completed,
+ async_impl_get_Result,
+ async_impl_Start,
+};
+
+DEFINE_IINSPECTABLE_OUTER( async_info, IAsyncInfo, struct async_info, IInspectable_outer )
+
+static HRESULT WINAPI async_info_get_Id( IAsyncInfo *iface, UINT32 *id )
+{
+ struct async_info *impl = impl_from_IAsyncInfo( iface );
+ HRESULT hr = S_OK;
+
+ TRACE( "iface %p, id %p.\n", iface, id );
+
+ EnterCriticalSection( &impl->cs );
+ if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL;
+ *id = 1;
+ LeaveCriticalSection( &impl->cs );
+
+ return hr;
+}
+
+static HRESULT WINAPI async_info_get_Status( IAsyncInfo *iface, AsyncStatus *status )
+{
+ struct async_info *impl = impl_from_IAsyncInfo( iface );
+ HRESULT hr = S_OK;
+
+ TRACE( "iface %p, status %p.\n", iface, status );
+
+ EnterCriticalSection( &impl->cs );
+ if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL;
+ *status = impl->status;
+ LeaveCriticalSection( &impl->cs );
+
+ return hr;
+}
+
+static HRESULT WINAPI async_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code )
+{
+ struct async_info *impl = impl_from_IAsyncInfo( iface );
+ HRESULT hr = S_OK;
+
+ TRACE( "iface %p, error_code %p.\n", iface, error_code );
+
+ EnterCriticalSection( &impl->cs );
+ if (impl->status == Closed) *error_code = hr = E_ILLEGAL_METHOD_CALL;
+ else *error_code = impl->hr;
+ LeaveCriticalSection( &impl->cs );
+
+ return hr;
+}
+
+static HRESULT WINAPI async_info_Cancel( IAsyncInfo *iface )
+{
+ struct async_info *impl = impl_from_IAsyncInfo( iface );
+ HRESULT hr = S_OK;
+
+ TRACE( "iface %p.\n", iface );
+
+ EnterCriticalSection( &impl->cs );
+ if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL;
+ else if (impl->status == Started) impl->status = Canceled;
+ LeaveCriticalSection( &impl->cs );
+
+ return hr;
+}
+
+static HRESULT WINAPI async_info_Close( IAsyncInfo *iface )
+{
+ struct async_info *impl = impl_from_IAsyncInfo( iface );
+ HRESULT hr = S_OK;
+
+ TRACE( "iface %p.\n", iface );
+
+ EnterCriticalSection( &impl->cs );
+ if (impl->status == Started)
+ hr = E_ILLEGAL_STATE_CHANGE;
+ else if (impl->status != Closed)
+ {
+ CloseThreadpoolWork( impl->async_run_work );
+ impl->async_run_work = NULL;
+ impl->status = Closed;
+ }
+ LeaveCriticalSection( &impl->cs );
+
+ return hr;
+}
+
+static const struct IAsyncInfoVtbl async_info_vtbl =
+{
+ /* IUnknown methods */
+ async_info_QueryInterface,
+ async_info_AddRef,
+ async_info_Release,
+ /* IInspectable methods */
+ async_info_GetIids,
+ async_info_GetRuntimeClassName,
+ async_info_GetTrustLevel,
+ /* IAsyncInfo */
+ async_info_get_Id,
+ async_info_get_Status,
+ async_info_get_ErrorCode,
+ async_info_Cancel,
+ async_info_Close,
+};
+
+static void CALLBACK async_info_callback( TP_CALLBACK_INSTANCE *instance, void *iface, TP_WORK *work )
+{
+ struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface );
+ IInspectable *operation = impl->IInspectable_outer;
+ PROPVARIANT result;
+ HRESULT hr;
+
+ hr = impl->callback( impl->invoker, impl->param, &result );
+
+ EnterCriticalSection( &impl->cs );
+ if (impl->status != Closed) impl->status = FAILED(hr) ? Error : Completed;
+ PropVariantCopy( &impl->result, &result );
+ impl->hr = hr;
+
+ if (impl->handler != NULL && impl->handler != HANDLER_NOT_SET)
+ {
+ IWineAsyncOperationCompletedHandler *handler = impl->handler;
+ AsyncStatus status = impl->status;
+ impl->handler = NULL; /* Prevent concurrent invoke. */
+ LeaveCriticalSection( &impl->cs );
+
+ IWineAsyncOperationCompletedHandler_Invoke( handler, operation, status );
+ IWineAsyncOperationCompletedHandler_Release( handler );
+ }
+ else LeaveCriticalSection( &impl->cs );
+
+ /* release refcount acquired in Start */
+ IInspectable_Release( operation );
+
+ PropVariantClear( &result );
+}
+
+static HRESULT async_info_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback,
+ IInspectable *outer, IWineAsyncInfoImpl **out )
+{
+ struct async_info *impl;
+
+ if (!(impl = calloc( 1, sizeof(struct async_info) ))) return E_OUTOFMEMORY;
+ impl->IWineAsyncInfoImpl_iface.lpVtbl = &async_impl_vtbl;
+ impl->IAsyncInfo_iface.lpVtbl = &async_info_vtbl;
+ impl->IInspectable_outer = outer;
+ impl->ref = 1;
+
+ impl->callback = callback;
+ impl->handler = HANDLER_NOT_SET;
+ impl->status = Started;
+ if (!(impl->async_run_work = CreateThreadpoolWork( async_info_callback, &impl->IWineAsyncInfoImpl_iface, NULL )))
+ return HRESULT_FROM_WIN32( GetLastError() );
+
+ if ((impl->invoker = invoker)) IUnknown_AddRef( impl->invoker );
+ if ((impl->param = param)) IUnknown_AddRef( impl->param );
+
+ InitializeCriticalSection( &impl->cs );
+ impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": async_info.cs" );
+
+ *out = &impl->IWineAsyncInfoImpl_iface;
+ return S_OK;
+}
+
+struct async_bool
+{
+ IAsyncOperation_boolean IAsyncOperation_boolean_iface;
+ IWineAsyncInfoImpl *IWineAsyncInfoImpl_inner;
+ LONG ref;
+};
+
+static inline struct async_bool *impl_from_IAsyncOperation_boolean( IAsyncOperation_boolean *iface )
+{
+ return CONTAINING_RECORD( iface, struct async_bool, IAsyncOperation_boolean_iface );
+}
+
+static HRESULT WINAPI async_bool_QueryInterface( IAsyncOperation_boolean *iface, REFIID iid, void **out )
+{
+ struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IAsyncOperation_boolean ))
+ {
+ IInspectable_AddRef( (*out = &impl->IAsyncOperation_boolean_iface) );
+ return S_OK;
+ }
+
+ return IWineAsyncInfoImpl_QueryInterface( impl->IWineAsyncInfoImpl_inner, iid, out );
+}
+
+static ULONG WINAPI async_bool_AddRef( IAsyncOperation_boolean *iface )
+{
+ struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p, ref %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI async_bool_Release( IAsyncOperation_boolean *iface )
+{
+ struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+ TRACE( "iface %p, ref %lu.\n", iface, ref );
+
+ if (!ref)
+ {
+ /* guard against re-entry if inner releases an outer iface */
+ InterlockedIncrement( &impl->ref );
+ IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner );
+ free( impl );
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI async_bool_GetIids( IAsyncOperation_boolean *iface, ULONG *iid_count, IID **iids )
+{
+ FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI async_bool_GetRuntimeClassName( IAsyncOperation_boolean *iface, HSTRING *class_name )
+{
+ return WindowsCreateString( L"Windows.Foundation.IAsyncOperation`1<Boolean>",
+ ARRAY_SIZE(L"Windows.Foundation.IAsyncOperation`1<Boolean>"),
+ class_name );
+}
+
+static HRESULT WINAPI async_bool_GetTrustLevel( IAsyncOperation_boolean *iface, TrustLevel *trust_level )
+{
+ FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI async_bool_put_Completed( IAsyncOperation_boolean *iface, IAsyncOperationCompletedHandler_boolean *bool_handler )
+{
+ IWineAsyncOperationCompletedHandler *handler = (IWineAsyncOperationCompletedHandler *)bool_handler;
+ struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface );
+ TRACE( "iface %p, handler %p.\n", iface, handler );
+ return IWineAsyncInfoImpl_put_Completed( impl->IWineAsyncInfoImpl_inner, (IWineAsyncOperationCompletedHandler *)handler );
+}
+
+static HRESULT WINAPI async_bool_get_Completed( IAsyncOperation_boolean *iface, IAsyncOperationCompletedHandler_boolean **bool_handler )
+{
+ IWineAsyncOperationCompletedHandler **handler = (IWineAsyncOperationCompletedHandler **)bool_handler;
+ struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface );
+ TRACE( "iface %p, handler %p.\n", iface, handler );
+ return IWineAsyncInfoImpl_get_Completed( impl->IWineAsyncInfoImpl_inner, (IWineAsyncOperationCompletedHandler **)handler );
+}
+
+static HRESULT WINAPI async_bool_GetResults( IAsyncOperation_boolean *iface, BOOLEAN *results )
+{
+ struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface );
+ PROPVARIANT result = {.vt = VT_BOOL};
+ HRESULT hr;
+
+ TRACE( "iface %p, results %p.\n", iface, results );
+
+ hr = IWineAsyncInfoImpl_get_Result( impl->IWineAsyncInfoImpl_inner, &result );
+
+ *results = result.boolVal;
+ PropVariantClear( &result );
+ return hr;
+}
+
+static const struct IAsyncOperation_booleanVtbl async_bool_vtbl =
+{
+ /* IUnknown methods */
+ async_bool_QueryInterface,
+ async_bool_AddRef,
+ async_bool_Release,
+ /* IInspectable methods */
+ async_bool_GetIids,
+ async_bool_GetRuntimeClassName,
+ async_bool_GetTrustLevel,
+ /* IAsyncOperation<boolean> */
+ async_bool_put_Completed,
+ async_bool_get_Completed,
+ async_bool_GetResults,
+};
+
+HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback,
+ IAsyncOperation_boolean **out )
+{
+ struct async_bool *impl;
+ HRESULT hr;
+
+ *out = NULL;
+ if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
+ impl->IAsyncOperation_boolean_iface.lpVtbl = &async_bool_vtbl;
+ impl->ref = 1;
+
+ if (FAILED(hr = async_info_create( invoker, param, callback, (IInspectable *)&impl->IAsyncOperation_boolean_iface, &impl->IWineAsyncInfoImpl_inner )) ||
+ FAILED(hr = IWineAsyncInfoImpl_Start( impl->IWineAsyncInfoImpl_inner )))
+ {
+ if (impl->IWineAsyncInfoImpl_inner) IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner );
+ free( impl );
+ return hr;
+ }
+
+ *out = &impl->IAsyncOperation_boolean_iface;
+ TRACE( "created IAsyncOperation_boolean %p\n", *out );
+ return S_OK;
+}
+
+struct async_result
+{
+ IAsyncOperation_ForceFeedbackLoadEffectResult IAsyncOperation_ForceFeedbackLoadEffectResult_iface;
+ IWineAsyncInfoImpl *IWineAsyncInfoImpl_inner;
+ LONG ref;
+};
+
+static inline struct async_result *impl_from_IAsyncOperation_ForceFeedbackLoadEffectResult( IAsyncOperation_ForceFeedbackLoadEffectResult *iface )
+{
+ return CONTAINING_RECORD( iface, struct async_result, IAsyncOperation_ForceFeedbackLoadEffectResult_iface );
+}
+
+static HRESULT WINAPI async_result_QueryInterface( IAsyncOperation_ForceFeedbackLoadEffectResult *iface, REFIID iid, void **out )
+{
+ struct async_result *impl = impl_from_IAsyncOperation_ForceFeedbackLoadEffectResult( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IAsyncOperation_ForceFeedbackLoadEffectResult ))
+ {
+ IInspectable_AddRef( (*out = &impl->IAsyncOperation_ForceFeedbackLoadEffectResult_iface) );
+ return S_OK;
+ }
+
+ return IWineAsyncInfoImpl_QueryInterface( impl->IWineAsyncInfoImpl_inner, iid, out );
+}
+
+static ULONG WINAPI async_result_AddRef( IAsyncOperation_ForceFeedbackLoadEffectResult *iface )
+{
+ struct async_result *impl = impl_from_IAsyncOperation_ForceFeedbackLoadEffectResult( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p, ref %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI async_result_Release( IAsyncOperation_ForceFeedbackLoadEffectResult *iface )
+{
+ struct async_result *impl = impl_from_IAsyncOperation_ForceFeedbackLoadEffectResult( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+ TRACE( "iface %p, ref %lu.\n", iface, ref );
+
+ if (!ref)
+ {
+ /* guard against re-entry if inner releases an outer iface */
+ InterlockedIncrement( &impl->ref );
+ IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner );
+ free( impl );
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI async_result_GetIids( IAsyncOperation_ForceFeedbackLoadEffectResult *iface, ULONG *iid_count, IID **iids )
+{
+ FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI async_result_GetRuntimeClassName( IAsyncOperation_ForceFeedbackLoadEffectResult *iface, HSTRING *class_name )
+{
+ return WindowsCreateString( L"Windows.Foundation.IAsyncOperation`1<Windows.Gaming.Input.ForceFeedback.ForceFeedbackLoadEffectResult>",
+ ARRAY_SIZE(L"Windows.Foundation.IAsyncOperation`1<Windows.Gaming.Input.ForceFeedback.ForceFeedbackLoadEffectResult>"),
+ class_name );
+}
+
+static HRESULT WINAPI async_result_GetTrustLevel( IAsyncOperation_ForceFeedbackLoadEffectResult *iface, TrustLevel *trust_level )
+{
+ FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI async_result_put_Completed( IAsyncOperation_ForceFeedbackLoadEffectResult *iface, IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult *handler )
+{
+ struct async_result *impl = impl_from_IAsyncOperation_ForceFeedbackLoadEffectResult( iface );
+ TRACE( "iface %p, handler %p.\n", iface, handler );
+ return IWineAsyncInfoImpl_put_Completed( impl->IWineAsyncInfoImpl_inner, (IWineAsyncOperationCompletedHandler *)handler );
+}
+
+static HRESULT WINAPI async_result_get_Completed( IAsyncOperation_ForceFeedbackLoadEffectResult *iface, IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult **handler )
+{
+ struct async_result *impl = impl_from_IAsyncOperation_ForceFeedbackLoadEffectResult( iface );
+ TRACE( "iface %p, handler %p.\n", iface, handler );
+ return IWineAsyncInfoImpl_get_Completed( impl->IWineAsyncInfoImpl_inner, (IWineAsyncOperationCompletedHandler **)handler );
+}
+
+static HRESULT WINAPI async_result_GetResults( IAsyncOperation_ForceFeedbackLoadEffectResult *iface, ForceFeedbackLoadEffectResult *results )
+{
+ struct async_result *impl = impl_from_IAsyncOperation_ForceFeedbackLoadEffectResult( iface );
+ PROPVARIANT result = {.vt = VT_UI4};
+ HRESULT hr;
+
+ TRACE( "iface %p, results %p.\n", iface, results );
+
+ hr = IWineAsyncInfoImpl_get_Result( impl->IWineAsyncInfoImpl_inner, &result );
+
+ *results = result.ulVal;
+ PropVariantClear( &result );
+ return hr;
+}
+
+static const struct IAsyncOperation_ForceFeedbackLoadEffectResultVtbl async_result_vtbl =
+{
+ /* IUnknown methods */
+ async_result_QueryInterface,
+ async_result_AddRef,
+ async_result_Release,
+ /* IInspectable methods */
+ async_result_GetIids,
+ async_result_GetRuntimeClassName,
+ async_result_GetTrustLevel,
+ /* IAsyncOperation<ForceFeedbackLoadEffectResult> */
+ async_result_put_Completed,
+ async_result_get_Completed,
+ async_result_GetResults,
+};
+
+HRESULT async_operation_effect_result_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback,
+ IAsyncOperation_ForceFeedbackLoadEffectResult **out )
+{
+ struct async_result *impl;
+ HRESULT hr;
+
+ *out = NULL;
+ if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
+ impl->IAsyncOperation_ForceFeedbackLoadEffectResult_iface.lpVtbl = &async_result_vtbl;
+ impl->ref = 1;
+
+ if (FAILED(hr = async_info_create( invoker, param, callback, (IInspectable *)&impl->IAsyncOperation_ForceFeedbackLoadEffectResult_iface, &impl->IWineAsyncInfoImpl_inner )) ||
+ FAILED(hr = IWineAsyncInfoImpl_Start( impl->IWineAsyncInfoImpl_inner )))
+ {
+ if (impl->IWineAsyncInfoImpl_inner) IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner );
+ free( impl );
+ return hr;
+ }
+
+ *out = &impl->IAsyncOperation_ForceFeedbackLoadEffectResult_iface;
+ TRACE( "created IAsyncOperation_ForceFeedbackLoadEffectResult %p\n", *out );
+ return S_OK;
+}
diff --git a/dlls/windows.gaming.input/classes.idl b/dlls/windows.gaming.input/classes.idl
index ca3bd5d8dd7..3172def88f5 100644
--- wine/dlls/windows.gaming.input/classes.idl
+++ wine/dlls/windows.gaming.input/classes.idl
@@ -29,6 +29,7 @@ import "asyncinfo.idl";
import "eventtoken.idl";
import "windowscontracts.idl";
import "windows.foundation.idl";
+import "windows.foundation.numerics.idl";
import "windows.devices.haptics.idl";
import "windows.gaming.input.forcefeedback.idl";
import "windows.system.idl";
@@ -36,4 +37,5 @@ import "windows.devices.power.idl";
#define DO_NO_IMPORTS
#include "windows.gaming.input.idl"
+#include "windows.gaming.ui.idl"
#include "windows.gaming.input.custom.idl"
diff --git a/dlls/windows.gaming.input/condition_effect.c b/dlls/windows.gaming.input/condition_effect.c
new file mode 100644
index 00000000000..c3a5a1fcd8b
--- /dev/null
+++ wine/dlls/windows.gaming.input/condition_effect.c
@@ -0,0 +1,288 @@
+/* WinRT Windows.Gaming.Input implementation
+ *
+ * Copyright 2022 Rémi Bernon for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "private.h"
+#include "provider.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(input);
+
+struct condition_effect
+{
+ IConditionForceEffect IConditionForceEffect_iface;
+ IWineForceFeedbackEffectImpl *IWineForceFeedbackEffectImpl_inner;
+ LONG ref;
+
+ ConditionForceEffectKind kind;
+};
+
+static inline struct condition_effect *impl_from_IConditionForceEffect( IConditionForceEffect *iface )
+{
+ return CONTAINING_RECORD( iface, struct condition_effect, IConditionForceEffect_iface );
+}
+
+static HRESULT WINAPI effect_QueryInterface( IConditionForceEffect *iface, REFIID iid, void **out )
+{
+ struct condition_effect *impl = impl_from_IConditionForceEffect( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IConditionForceEffect ))
+ {
+ IInspectable_AddRef( (*out = &impl->IConditionForceEffect_iface) );
+ return S_OK;
+ }
+
+ return IWineForceFeedbackEffectImpl_QueryInterface( impl->IWineForceFeedbackEffectImpl_inner, iid, out );
+}
+
+static ULONG WINAPI effect_AddRef( IConditionForceEffect *iface )
+{
+ struct condition_effect *impl = impl_from_IConditionForceEffect( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI effect_Release( IConditionForceEffect *iface )
+{
+ struct condition_effect *impl = impl_from_IConditionForceEffect( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+
+ TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+
+ if (!ref)
+ {
+ /* guard against re-entry if inner releases an outer iface */
+ InterlockedIncrement( &impl->ref );
+ IWineForceFeedbackEffectImpl_Release( impl->IWineForceFeedbackEffectImpl_inner );
+ free( impl );
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI effect_GetIids( IConditionForceEffect *iface, ULONG *iid_count, IID **iids )
+{
+ FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI effect_GetRuntimeClassName( IConditionForceEffect *iface, HSTRING *class_name )
+{
+ return WindowsCreateString( RuntimeClass_Windows_Gaming_Input_ForceFeedback_ConditionForceEffect,
+ ARRAY_SIZE(RuntimeClass_Windows_Gaming_Input_ForceFeedback_ConditionForceEffect),
+ class_name );
+}
+
+static HRESULT WINAPI effect_GetTrustLevel( IConditionForceEffect *iface, TrustLevel *trust_level )
+{
+ FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI effect_get_Kind( IConditionForceEffect *iface, ConditionForceEffectKind *kind )
+{
+ struct condition_effect *impl = impl_from_IConditionForceEffect( iface );
+ TRACE( "iface %p, kind %p.\n", iface, kind );
+ *kind = impl->kind;
+ return S_OK;
+}
+
+static HRESULT WINAPI effect_SetParameters( IConditionForceEffect *iface, Vector3 direction, FLOAT positive_coeff, FLOAT negative_coeff,
+ FLOAT max_positive_magnitude, FLOAT max_negative_magnitude, FLOAT deadzone, FLOAT bias )
+{
+ struct condition_effect *impl = impl_from_IConditionForceEffect( iface );
+ WineForceFeedbackEffectParameters params =
+ {
+ .condition =
+ {
+ .type = WineForceFeedbackEffectType_Condition + impl->kind,
+ .direction = direction,
+ .positive_coeff = positive_coeff,
+ .negative_coeff = negative_coeff,
+ .max_positive_magnitude = max_positive_magnitude,
+ .max_negative_magnitude = max_negative_magnitude,
+ .deadzone = deadzone,
+ .bias = bias,
+ },
+ };
+
+ TRACE( "iface %p, direction %s, positive_coeff %f, negative_coeff %f, max_positive_magnitude %f, max_negative_magnitude %f, deadzone %f, bias %f.\n",
+ iface, debugstr_vector3( &direction ), positive_coeff, negative_coeff, max_positive_magnitude, max_negative_magnitude, deadzone, bias );
+
+ return IWineForceFeedbackEffectImpl_put_Parameters( impl->IWineForceFeedbackEffectImpl_inner, params, NULL );
+}
+
+static const struct IConditionForceEffectVtbl effect_vtbl =
+{
+ effect_QueryInterface,
+ effect_AddRef,
+ effect_Release,
+ /* IInspectable methods */
+ effect_GetIids,
+ effect_GetRuntimeClassName,
+ effect_GetTrustLevel,
+ /* IConditionForceEffect methods */
+ effect_get_Kind,
+ effect_SetParameters,
+};
+
+struct condition_factory
+{
+ IActivationFactory IActivationFactory_iface;
+ IConditionForceEffectFactory IConditionForceEffectFactory_iface;
+ LONG ref;
+};
+
+static inline struct condition_factory *impl_from_IActivationFactory( IActivationFactory *iface )
+{
+ return CONTAINING_RECORD( iface, struct condition_factory, IActivationFactory_iface );
+}
+
+static HRESULT WINAPI activation_QueryInterface( IActivationFactory *iface, REFIID iid, void **out )
+{
+ struct condition_factory *impl = impl_from_IActivationFactory( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IActivationFactory ))
+ {
+ IInspectable_AddRef( (*out = &impl->IActivationFactory_iface) );
+ return S_OK;
+ }
+
+ if (IsEqualGUID( iid, &IID_IConditionForceEffectFactory ))
+ {
+ IInspectable_AddRef( (*out = &impl->IConditionForceEffectFactory_iface) );
+ return S_OK;
+ }
+
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI activation_AddRef( IActivationFactory *iface )
+{
+ struct condition_factory *impl = impl_from_IActivationFactory( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI activation_Release( IActivationFactory *iface )
+{
+ struct condition_factory *impl = impl_from_IActivationFactory( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+ TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static HRESULT WINAPI activation_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids )
+{
+ FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI activation_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name )
+{
+ FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI activation_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level )
+{
+ FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI activation_ActivateInstance( IActivationFactory *iface, IInspectable **instance )
+{
+ FIXME( "iface %p, instance %p stub!\n", iface, instance );
+ return E_NOTIMPL;
+}
+
+static const struct IActivationFactoryVtbl activation_vtbl =
+{
+ activation_QueryInterface,
+ activation_AddRef,
+ activation_Release,
+ /* IInspectable methods */
+ activation_GetIids,
+ activation_GetRuntimeClassName,
+ activation_GetTrustLevel,
+ /* IActivationFactory methods */
+ activation_ActivateInstance,
+};
+
+DEFINE_IINSPECTABLE( factory, IConditionForceEffectFactory, struct condition_factory, IActivationFactory_iface )
+
+static HRESULT WINAPI factory_CreateInstance( IConditionForceEffectFactory *iface, enum ConditionForceEffectKind kind, IForceFeedbackEffect **out )
+{
+ enum WineForceFeedbackEffectType type = WineForceFeedbackEffectType_Condition + kind;
+ struct condition_effect *impl;
+ HRESULT hr;
+
+ TRACE( "iface %p, kind %u, out %p.\n", iface, kind, out );
+
+ if (!(impl = calloc( 1, sizeof(struct condition_effect) ))) return E_OUTOFMEMORY;
+ impl->IConditionForceEffect_iface.lpVtbl = &effect_vtbl;
+ impl->ref = 1;
+ impl->kind = kind;
+
+ if (FAILED(hr = force_feedback_effect_create( type, (IInspectable *)&impl->IConditionForceEffect_iface, &impl->IWineForceFeedbackEffectImpl_inner )) ||
+ FAILED(hr = IConditionForceEffect_QueryInterface( &impl->IConditionForceEffect_iface, &IID_IForceFeedbackEffect, (void **)out )))
+ {
+ if (impl->IWineForceFeedbackEffectImpl_inner) IWineForceFeedbackEffectImpl_Release( impl->IWineForceFeedbackEffectImpl_inner );
+ free( impl );
+ return hr;
+ }
+
+ IConditionForceEffect_Release( &impl->IConditionForceEffect_iface );
+ TRACE( "created ConditionForceEffect %p\n", *out );
+ return S_OK;
+}
+
+static const struct IConditionForceEffectFactoryVtbl factory_vtbl =
+{
+ factory_QueryInterface,
+ factory_AddRef,
+ factory_Release,
+ /* IInspectable methods */
+ factory_GetIids,
+ factory_GetRuntimeClassName,
+ factory_GetTrustLevel,
+ /* IConditionForceEffectFactory methods */
+ factory_CreateInstance,
+};
+
+static struct condition_factory condition_statics =
+{
+ {&activation_vtbl},
+ {&factory_vtbl},
+ 1,
+};
+
+IInspectable *condition_effect_factory = (IInspectable *)&condition_statics.IActivationFactory_iface;
diff --git a/dlls/windows.gaming.input/constant_effect.c b/dlls/windows.gaming.input/constant_effect.c
new file mode 100644
index 00000000000..15763b30d67
--- /dev/null
+++ wine/dlls/windows.gaming.input/constant_effect.c
@@ -0,0 +1,275 @@
+/* WinRT Windows.Gaming.Input implementation
+ *
+ * Copyright 2022 Rémi Bernon for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "private.h"
+#include "provider.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(input);
+
+struct constant_effect
+{
+ IConstantForceEffect IConstantForceEffect_iface;
+ IWineForceFeedbackEffectImpl *IWineForceFeedbackEffectImpl_inner;
+ LONG ref;
+};
+
+static inline struct constant_effect *impl_from_IConstantForceEffect( IConstantForceEffect *iface )
+{
+ return CONTAINING_RECORD( iface, struct constant_effect, IConstantForceEffect_iface );
+}
+
+static HRESULT WINAPI effect_QueryInterface( IConstantForceEffect *iface, REFIID iid, void **out )
+{
+ struct constant_effect *impl = impl_from_IConstantForceEffect( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IConstantForceEffect ))
+ {
+ IInspectable_AddRef( (*out = &impl->IConstantForceEffect_iface) );
+ return S_OK;
+ }
+
+ return IWineForceFeedbackEffectImpl_QueryInterface( impl->IWineForceFeedbackEffectImpl_inner, iid, out );
+}
+
+static ULONG WINAPI effect_AddRef( IConstantForceEffect *iface )
+{
+ struct constant_effect *impl = impl_from_IConstantForceEffect( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI effect_Release( IConstantForceEffect *iface )
+{
+ struct constant_effect *impl = impl_from_IConstantForceEffect( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+
+ TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+
+ if (!ref)
+ {
+ /* guard against re-entry if inner releases an outer iface */
+ InterlockedIncrement( &impl->ref );
+ IWineForceFeedbackEffectImpl_Release( impl->IWineForceFeedbackEffectImpl_inner );
+ free( impl );
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI effect_GetIids( IConstantForceEffect *iface, ULONG *iid_count, IID **iids )
+{
+ FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI effect_GetRuntimeClassName( IConstantForceEffect *iface, HSTRING *class_name )
+{
+ return WindowsCreateString( RuntimeClass_Windows_Gaming_Input_ForceFeedback_ConstantForceEffect,
+ ARRAY_SIZE(RuntimeClass_Windows_Gaming_Input_ForceFeedback_ConstantForceEffect),
+ class_name );
+}
+
+static HRESULT WINAPI effect_GetTrustLevel( IConstantForceEffect *iface, TrustLevel *trust_level )
+{
+ FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI effect_SetParameters( IConstantForceEffect *iface, Vector3 direction, TimeSpan duration )
+{
+ WineForceFeedbackEffectParameters params =
+ {
+ .constant =
+ {
+ .type = WineForceFeedbackEffectType_Constant,
+ .direction = direction,
+ .duration = duration,
+ .repeat_count = 1,
+ .gain = 1.,
+ },
+ };
+ struct constant_effect *impl = impl_from_IConstantForceEffect( iface );
+
+ TRACE( "iface %p, direction %s, duration %I64u.\n", iface, debugstr_vector3( &direction ), duration.Duration );
+
+ return IWineForceFeedbackEffectImpl_put_Parameters( impl->IWineForceFeedbackEffectImpl_inner, params, NULL );
+}
+
+static HRESULT WINAPI effect_SetParametersWithEnvelope( IConstantForceEffect *iface, Vector3 direction, FLOAT attack_gain,
+ FLOAT sustain_gain, FLOAT release_gain, TimeSpan start_delay,
+ TimeSpan attack_duration, TimeSpan sustain_duration,
+ TimeSpan release_duration, UINT32 repeat_count )
+{
+ WineForceFeedbackEffectParameters params =
+ {
+ .constant =
+ {
+ .type = WineForceFeedbackEffectType_Constant,
+ .direction = direction,
+ .duration = {attack_duration.Duration + sustain_duration.Duration + release_duration.Duration},
+ .start_delay = start_delay,
+ .repeat_count = repeat_count,
+ .gain = sustain_gain,
+ },
+ };
+ WineForceFeedbackEffectEnvelope envelope =
+ {
+ .attack_gain = attack_gain,
+ .release_gain = release_gain,
+ .attack_duration = attack_duration,
+ .release_duration = release_duration,
+ };
+ struct constant_effect *impl = impl_from_IConstantForceEffect( iface );
+
+ TRACE( "iface %p, direction %s, attack_gain %f, sustain_gain %f, release_gain %f, start_delay %I64u, attack_duration %I64u, "
+ "sustain_duration %I64u, release_duration %I64u, repeat_count %u.\n", iface, debugstr_vector3( &direction ),
+ attack_gain, sustain_gain, release_gain, start_delay.Duration, attack_duration.Duration, sustain_duration.Duration,
+ release_duration.Duration, repeat_count );
+
+ return IWineForceFeedbackEffectImpl_put_Parameters( impl->IWineForceFeedbackEffectImpl_inner, params, &envelope );
+}
+
+static const struct IConstantForceEffectVtbl effect_vtbl =
+{
+ effect_QueryInterface,
+ effect_AddRef,
+ effect_Release,
+ /* IInspectable methods */
+ effect_GetIids,
+ effect_GetRuntimeClassName,
+ effect_GetTrustLevel,
+ /* IConstantForceEffect methods */
+ effect_SetParameters,
+ effect_SetParametersWithEnvelope,
+};
+
+struct constant_factory
+{
+ IActivationFactory IActivationFactory_iface;
+ LONG ref;
+};
+
+static inline struct constant_factory *impl_from_IActivationFactory( IActivationFactory *iface )
+{
+ return CONTAINING_RECORD( iface, struct constant_factory, IActivationFactory_iface );
+}
+
+static HRESULT WINAPI activation_QueryInterface( IActivationFactory *iface, REFIID iid, void **out )
+{
+ struct constant_factory *impl = impl_from_IActivationFactory( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IActivationFactory ))
+ {
+ IInspectable_AddRef( (*out = &impl->IActivationFactory_iface) );
+ return S_OK;
+ }
+
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI activation_AddRef( IActivationFactory *iface )
+{
+ struct constant_factory *impl = impl_from_IActivationFactory( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI activation_Release( IActivationFactory *iface )
+{
+ struct constant_factory *impl = impl_from_IActivationFactory( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+ TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static HRESULT WINAPI activation_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids )
+{
+ FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI activation_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name )
+{
+ FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI activation_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level )
+{
+ FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI activation_ActivateInstance( IActivationFactory *iface, IInspectable **instance )
+{
+ struct constant_effect *impl;
+ HRESULT hr;
+
+ TRACE( "iface %p, instance %p.\n", iface, instance );
+
+ if (!(impl = calloc( 1, sizeof(struct constant_effect) ))) return E_OUTOFMEMORY;
+ impl->IConstantForceEffect_iface.lpVtbl = &effect_vtbl;
+ impl->ref = 1;
+
+ if (FAILED(hr = force_feedback_effect_create( WineForceFeedbackEffectType_Constant, (IInspectable *)&impl->IConstantForceEffect_iface,
+ &impl->IWineForceFeedbackEffectImpl_inner )))
+ {
+ free( impl );
+ return hr;
+ }
+
+ *instance = (IInspectable *)&impl->IConstantForceEffect_iface;
+ TRACE( "created ConstantForceEffect %p\n", *instance );
+ return S_OK;
+}
+
+static const struct IActivationFactoryVtbl activation_vtbl =
+{
+ activation_QueryInterface,
+ activation_AddRef,
+ activation_Release,
+ /* IInspectable methods */
+ activation_GetIids,
+ activation_GetRuntimeClassName,
+ activation_GetTrustLevel,
+ /* IActivationFactory methods */
+ activation_ActivateInstance,
+};
+
+static struct constant_factory constant_statics =
+{
+ {&activation_vtbl},
+ 1,
+};
+
+IInspectable *constant_effect_factory = (IInspectable *)&constant_statics.IActivationFactory_iface;
diff --git a/dlls/windows.gaming.input/controller.c b/dlls/windows.gaming.input/controller.c
index 03a3ae398cf..bd3d441c445 100644
--- wine/dlls/windows.gaming.input/controller.c
+++ wine/dlls/windows.gaming.input/controller.c
@@ -99,7 +99,7 @@ static HRESULT WINAPI controller_QueryInterface( IGameControllerImpl *iface, REF
return S_OK;
}
- WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
*out = NULL;
return E_NOINTERFACE;
}
@@ -229,8 +229,32 @@ static HRESULT WINAPI raw_controller_get_ButtonCount( IRawGameController *iface,
static HRESULT WINAPI raw_controller_get_ForceFeedbackMotors( IRawGameController *iface, IVectorView_ForceFeedbackMotor **value )
{
- FIXME( "iface %p, value %p stub!\n", iface, value );
- return E_NOTIMPL;
+ static const struct vector_iids iids =
+ {
+ .vector = &IID_IVector_ForceFeedbackMotor,
+ .view = &IID_IVectorView_ForceFeedbackMotor,
+ .iterable = &IID_IIterable_ForceFeedbackMotor,
+ .iterator = &IID_IIterator_ForceFeedbackMotor,
+ };
+ struct controller *impl = impl_from_IRawGameController( iface );
+ IVector_ForceFeedbackMotor *vector;
+ IForceFeedbackMotor *motor;
+ HRESULT hr;
+
+ TRACE( "iface %p, value %p\n", iface, value );
+
+ if (FAILED(hr = vector_create( &iids, (void **)&vector ))) return hr;
+
+ if (SUCCEEDED(IWineGameControllerProvider_get_ForceFeedbackMotor( impl->wine_provider, &motor )) && motor)
+ {
+ hr = IVector_ForceFeedbackMotor_Append( vector, motor );
+ IForceFeedbackMotor_Release( motor );
+ }
+
+ if (SUCCEEDED(hr)) hr = IVector_ForceFeedbackMotor_GetView( vector, value );
+ IVector_ForceFeedbackMotor_Release( vector );
+
+ return hr;
}
static HRESULT WINAPI raw_controller_get_HardwareProductId( IRawGameController *iface, UINT16 *value )
diff --git a/dlls/windows.gaming.input/force_feedback.c b/dlls/windows.gaming.input/force_feedback.c
new file mode 100644
index 00000000000..f7a233b46d4
--- /dev/null
+++ wine/dlls/windows.gaming.input/force_feedback.c
@@ -0,0 +1,801 @@
+/* WinRT Windows.Gaming.Input implementation
+ *
+ * Copyright 2022 Rémi Bernon for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "private.h"
+
+#include "math.h"
+
+#include "ddk/hidsdi.h"
+#include "dinput.h"
+#include "hidusage.h"
+#include "provider.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(input);
+
+struct effect
+{
+ IWineForceFeedbackEffectImpl IWineForceFeedbackEffectImpl_iface;
+ IForceFeedbackEffect IForceFeedbackEffect_iface;
+ IInspectable *IInspectable_outer;
+ LONG ref;
+
+ CRITICAL_SECTION cs;
+ IDirectInputEffect *effect;
+
+ GUID type;
+ DWORD axes[3];
+ LONG directions[3];
+ ULONG repeat_count;
+ DICONSTANTFORCE constant_force;
+ DIRAMPFORCE ramp_force;
+ DICONDITION condition;
+ DIPERIODIC periodic;
+ DIENVELOPE envelope;
+ DIEFFECT params;
+};
+
+static inline struct effect *impl_from_IWineForceFeedbackEffectImpl( IWineForceFeedbackEffectImpl *iface )
+{
+ return CONTAINING_RECORD( iface, struct effect, IWineForceFeedbackEffectImpl_iface );
+}
+
+static HRESULT WINAPI effect_impl_QueryInterface( IWineForceFeedbackEffectImpl *iface, REFIID iid, void **out )
+{
+ struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IWineForceFeedbackEffectImpl ))
+ {
+ IWineForceFeedbackEffectImpl_AddRef( (*out = &impl->IWineForceFeedbackEffectImpl_iface) );
+ return S_OK;
+ }
+
+ if (IsEqualGUID( iid, &IID_IForceFeedbackEffect ))
+ {
+ IInspectable_AddRef( (*out = &impl->IForceFeedbackEffect_iface) );
+ return S_OK;
+ }
+
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI effect_impl_AddRef( IWineForceFeedbackEffectImpl *iface )
+{
+ struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI effect_impl_Release( IWineForceFeedbackEffectImpl *iface )
+{
+ struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+
+ TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+
+ if (!ref)
+ {
+ if (impl->effect) IDirectInputEffect_Release( impl->effect );
+ impl->cs.DebugInfo->Spare[0] = 0;
+ DeleteCriticalSection( &impl->cs );
+ free( impl );
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI effect_impl_put_Parameters( IWineForceFeedbackEffectImpl *iface, WineForceFeedbackEffectParameters params,
+ WineForceFeedbackEffectEnvelope *envelope )
+{
+ struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( iface );
+ DWORD count = 0;
+ HRESULT hr;
+
+ TRACE( "iface %p, params %p, envelope %p.\n", iface, &params, envelope );
+
+ EnterCriticalSection( &impl->cs );
+ switch (params.type)
+ {
+ case WineForceFeedbackEffectType_Constant:
+ impl->repeat_count = params.constant.repeat_count;
+ impl->constant_force.lMagnitude = round( params.constant.gain * params.constant.direction.X * 10000 );
+ impl->params.dwDuration = params.constant.duration.Duration / 10;
+ impl->params.dwStartDelay = params.constant.start_delay.Duration / 10;
+ if (impl->axes[count] == DIJOFS_X) impl->directions[count++] = round( -params.constant.direction.X * 10000 );
+ if (impl->axes[count] == DIJOFS_Y) impl->directions[count++] = round( -params.constant.direction.Y * 10000 );
+ if (impl->axes[count] == DIJOFS_Z) impl->directions[count++] = round( -params.constant.direction.Z * 10000 );
+ break;
+
+ case WineForceFeedbackEffectType_Ramp:
+ impl->repeat_count = params.ramp.repeat_count;
+ impl->ramp_force.lStart = round( params.ramp.gain * params.ramp.start_vector.X * 10000 );
+ impl->ramp_force.lEnd = round( params.ramp.gain * params.ramp.end_vector.X * 10000 );
+ impl->params.dwDuration = params.ramp.duration.Duration / 10;
+ impl->params.dwStartDelay = params.ramp.start_delay.Duration / 10;
+ if (impl->axes[count] == DIJOFS_X) impl->directions[count++] = round( -params.ramp.start_vector.X * 10000 );
+ if (impl->axes[count] == DIJOFS_Y) impl->directions[count++] = round( -params.ramp.start_vector.Y * 10000 );
+ if (impl->axes[count] == DIJOFS_Z) impl->directions[count++] = round( -params.ramp.start_vector.Z * 10000 );
+ break;
+
+ case WineForceFeedbackEffectType_Periodic_SineWave:
+ case WineForceFeedbackEffectType_Periodic_TriangleWave:
+ case WineForceFeedbackEffectType_Periodic_SquareWave:
+ case WineForceFeedbackEffectType_Periodic_SawtoothWaveDown:
+ case WineForceFeedbackEffectType_Periodic_SawtoothWaveUp:
+ impl->repeat_count = params.periodic.repeat_count;
+ impl->periodic.dwMagnitude = round( params.periodic.gain * 10000 );
+ impl->periodic.dwPeriod = 1000000 / params.periodic.frequency;
+ impl->periodic.dwPhase = round( params.periodic.phase * 36000 );
+ impl->periodic.lOffset = round( params.periodic.bias * 10000 );
+ impl->params.dwDuration = params.periodic.duration.Duration / 10;
+ impl->params.dwStartDelay = params.periodic.start_delay.Duration / 10;
+ if (impl->axes[count] == DIJOFS_X) impl->directions[count++] = round( -params.periodic.direction.X * 10000 );
+ if (impl->axes[count] == DIJOFS_Y) impl->directions[count++] = round( -params.periodic.direction.Y * 10000 );
+ if (impl->axes[count] == DIJOFS_Z) impl->directions[count++] = round( -params.periodic.direction.Z * 10000 );
+ break;
+
+ case WineForceFeedbackEffectType_Condition_Spring:
+ case WineForceFeedbackEffectType_Condition_Damper:
+ case WineForceFeedbackEffectType_Condition_Inertia:
+ case WineForceFeedbackEffectType_Condition_Friction:
+ impl->repeat_count = 1;
+ impl->condition.lPositiveCoefficient = round( atan( params.condition.positive_coeff ) / M_PI_2 * 10000 );
+ impl->condition.lNegativeCoefficient = round( atan( params.condition.negative_coeff ) / M_PI_2 * 10000 );
+ impl->condition.dwPositiveSaturation = round( params.condition.max_positive_magnitude * 10000 );
+ impl->condition.dwNegativeSaturation = round( params.condition.max_negative_magnitude * 10000 );
+ impl->condition.lDeadBand = round( params.condition.deadzone * 10000 );
+ impl->condition.lOffset = round( params.condition.bias * 10000 );
+ impl->params.dwDuration = -1;
+ impl->params.dwStartDelay = 0;
+ if (impl->axes[count] == DIJOFS_X) impl->directions[count++] = round( params.condition.direction.X * 10000 );
+ if (impl->axes[count] == DIJOFS_Y) impl->directions[count++] = round( params.condition.direction.Y * 10000 );
+ if (impl->axes[count] == DIJOFS_Z) impl->directions[count++] = round( params.condition.direction.Z * 10000 );
+ break;
+ }
+
+ if (!envelope) impl->params.lpEnvelope = NULL;
+ else
+ {
+ impl->envelope.dwAttackTime = envelope->attack_duration.Duration / 10;
+ impl->envelope.dwAttackLevel = round( envelope->attack_gain * 10000 );
+ impl->envelope.dwFadeTime = impl->params.dwDuration - envelope->release_duration.Duration / 10;
+ impl->envelope.dwFadeLevel = round( envelope->release_gain * 10000 );
+ impl->params.lpEnvelope = &impl->envelope;
+ }
+
+ if (!impl->effect) hr = S_OK;
+ else hr = IDirectInputEffect_SetParameters( impl->effect, &impl->params, DIEP_ALLPARAMS & ~DIEP_AXES );
+ LeaveCriticalSection( &impl->cs );
+
+ return hr;
+}
+
+static const struct IWineForceFeedbackEffectImplVtbl effect_impl_vtbl =
+{
+ effect_impl_QueryInterface,
+ effect_impl_AddRef,
+ effect_impl_Release,
+ /* IWineForceFeedbackEffectImpl methods */
+ effect_impl_put_Parameters,
+};
+
+DEFINE_IINSPECTABLE_OUTER( effect, IForceFeedbackEffect, struct effect, IInspectable_outer )
+
+static HRESULT WINAPI effect_get_Gain( IForceFeedbackEffect *iface, DOUBLE *value )
+{
+ struct effect *impl = impl_from_IForceFeedbackEffect( iface );
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ EnterCriticalSection( &impl->cs );
+ *value = impl->params.dwGain / 10000.;
+ LeaveCriticalSection( &impl->cs );
+
+ return S_OK;
+}
+
+static HRESULT WINAPI effect_put_Gain( IForceFeedbackEffect *iface, DOUBLE value )
+{
+ struct effect *impl = impl_from_IForceFeedbackEffect( iface );
+ HRESULT hr;
+
+ TRACE( "iface %p, value %f.\n", iface, value );
+
+ EnterCriticalSection( &impl->cs );
+ impl->params.dwGain = round( value * 10000 );
+ if (!impl->effect) hr = S_FALSE;
+ else hr = IDirectInputEffect_SetParameters( impl->effect, &impl->params, DIEP_GAIN );
+ LeaveCriticalSection( &impl->cs );
+
+ return hr;
+}
+
+static HRESULT WINAPI effect_get_State( IForceFeedbackEffect *iface, ForceFeedbackEffectState *value )
+{
+ struct effect *impl = impl_from_IForceFeedbackEffect( iface );
+ DWORD status;
+ HRESULT hr;
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ EnterCriticalSection( &impl->cs );
+ if (!impl->effect)
+ *value = ForceFeedbackEffectState_Stopped;
+ else if (FAILED(hr = IDirectInputEffect_GetEffectStatus( impl->effect, &status )))
+ *value = ForceFeedbackEffectState_Faulted;
+ else
+ {
+ if (status == DIEGES_PLAYING) *value = ForceFeedbackEffectState_Running;
+ else *value = ForceFeedbackEffectState_Stopped;
+ }
+ LeaveCriticalSection( &impl->cs );
+
+ return S_OK;
+}
+
+static HRESULT WINAPI effect_Start( IForceFeedbackEffect *iface )
+{
+ struct effect *impl = impl_from_IForceFeedbackEffect( iface );
+ HRESULT hr = E_UNEXPECTED;
+ DWORD flags = 0;
+
+ TRACE( "iface %p.\n", iface );
+
+ EnterCriticalSection( &impl->cs );
+ if (impl->effect) hr = IDirectInputEffect_Start( impl->effect, impl->repeat_count, flags );
+ LeaveCriticalSection( &impl->cs );
+
+ return hr;
+}
+
+static HRESULT WINAPI effect_Stop( IForceFeedbackEffect *iface )
+{
+ struct effect *impl = impl_from_IForceFeedbackEffect( iface );
+ HRESULT hr = E_UNEXPECTED;
+
+ TRACE( "iface %p.\n", iface );
+
+ EnterCriticalSection( &impl->cs );
+ if (impl->effect) hr = IDirectInputEffect_Stop( impl->effect );
+ LeaveCriticalSection( &impl->cs );
+
+ return hr;
+}
+
+static const struct IForceFeedbackEffectVtbl effect_vtbl =
+{
+ effect_QueryInterface,
+ effect_AddRef,
+ effect_Release,
+ /* IInspectable methods */
+ effect_GetIids,
+ effect_GetRuntimeClassName,
+ effect_GetTrustLevel,
+ /* IForceFeedbackEffect methods */
+ effect_get_Gain,
+ effect_put_Gain,
+ effect_get_State,
+ effect_Start,
+ effect_Stop,
+};
+
+HRESULT force_feedback_effect_create( enum WineForceFeedbackEffectType type, IInspectable *outer, IWineForceFeedbackEffectImpl **out )
+{
+ struct effect *impl;
+
+ TRACE( "outer %p, out %p\n", outer, out );
+
+ if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
+ impl->IWineForceFeedbackEffectImpl_iface.lpVtbl = &effect_impl_vtbl;
+ impl->IForceFeedbackEffect_iface.lpVtbl = &effect_vtbl;
+ impl->IInspectable_outer = outer;
+ impl->ref = 1;
+
+ switch (type)
+ {
+ case WineForceFeedbackEffectType_Constant:
+ impl->type = GUID_ConstantForce;
+ impl->params.lpvTypeSpecificParams = &impl->constant_force;
+ impl->params.cbTypeSpecificParams = sizeof(impl->constant_force);
+ break;
+
+ case WineForceFeedbackEffectType_Ramp:
+ impl->type = GUID_RampForce;
+ impl->params.lpvTypeSpecificParams = &impl->ramp_force;
+ impl->params.cbTypeSpecificParams = sizeof(impl->ramp_force);
+ break;
+
+ case WineForceFeedbackEffectType_Periodic_SineWave:
+ impl->type = GUID_Sine;
+ goto WineForceFeedbackEffectType_Periodic;
+ case WineForceFeedbackEffectType_Periodic_TriangleWave:
+ impl->type = GUID_Triangle;
+ goto WineForceFeedbackEffectType_Periodic;
+ case WineForceFeedbackEffectType_Periodic_SquareWave:
+ impl->type = GUID_Square;
+ goto WineForceFeedbackEffectType_Periodic;
+ case WineForceFeedbackEffectType_Periodic_SawtoothWaveDown:
+ impl->type = GUID_SawtoothDown;
+ goto WineForceFeedbackEffectType_Periodic;
+ case WineForceFeedbackEffectType_Periodic_SawtoothWaveUp:
+ impl->type = GUID_SawtoothUp;
+ goto WineForceFeedbackEffectType_Periodic;
+ WineForceFeedbackEffectType_Periodic:
+ impl->params.lpvTypeSpecificParams = &impl->periodic;
+ impl->params.cbTypeSpecificParams = sizeof(impl->periodic);
+ break;
+
+ case WineForceFeedbackEffectType_Condition_Spring:
+ impl->type = GUID_Spring;
+ goto WineForceFeedbackEffectType_Condition;
+ case WineForceFeedbackEffectType_Condition_Damper:
+ impl->type = GUID_Damper;
+ goto WineForceFeedbackEffectType_Condition;
+ case WineForceFeedbackEffectType_Condition_Inertia:
+ impl->type = GUID_Inertia;
+ goto WineForceFeedbackEffectType_Condition;
+ case WineForceFeedbackEffectType_Condition_Friction:
+ impl->type = GUID_Friction;
+ goto WineForceFeedbackEffectType_Condition;
+ WineForceFeedbackEffectType_Condition:
+ impl->params.lpvTypeSpecificParams = &impl->condition;
+ impl->params.cbTypeSpecificParams = sizeof(impl->condition);
+ break;
+ }
+
+ impl->envelope.dwSize = sizeof(DIENVELOPE);
+ impl->params.dwSize = sizeof(DIEFFECT);
+ impl->params.rgdwAxes = impl->axes;
+ impl->params.rglDirection = impl->directions;
+ impl->params.dwTriggerButton = -1;
+ impl->params.dwGain = 10000;
+ impl->params.dwFlags = DIEFF_CARTESIAN|DIEFF_OBJECTOFFSETS;
+ impl->params.cAxes = -1;
+ impl->axes[0] = DIJOFS_X;
+ impl->axes[1] = DIJOFS_Y;
+ impl->axes[2] = DIJOFS_Z;
+
+ InitializeCriticalSection( &impl->cs );
+ impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": effect.cs" );
+
+ *out = &impl->IWineForceFeedbackEffectImpl_iface;
+ TRACE( "created ForceFeedbackEffect %p\n", *out );
+ return S_OK;
+}
+
+struct motor
+{
+ IForceFeedbackMotor IForceFeedbackMotor_iface;
+ LONG ref;
+
+ IDirectInputDevice8W *device;
+};
+
+static inline struct motor *impl_from_IForceFeedbackMotor( IForceFeedbackMotor *iface )
+{
+ return CONTAINING_RECORD( iface, struct motor, IForceFeedbackMotor_iface );
+}
+
+static HRESULT WINAPI motor_QueryInterface( IForceFeedbackMotor *iface, REFIID iid, void **out )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IForceFeedbackMotor ))
+ {
+ IInspectable_AddRef( (*out = &impl->IForceFeedbackMotor_iface) );
+ return S_OK;
+ }
+
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI motor_AddRef( IForceFeedbackMotor *iface )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI motor_Release( IForceFeedbackMotor *iface )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+
+ TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+
+ if (!ref)
+ {
+ IDirectInputDevice8_Release( impl->device );
+ free( impl );
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI motor_GetIids( IForceFeedbackMotor *iface, ULONG *iid_count, IID **iids )
+{
+ FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI motor_GetRuntimeClassName( IForceFeedbackMotor *iface, HSTRING *class_name )
+{
+ return WindowsCreateString( RuntimeClass_Windows_Gaming_Input_ForceFeedback_ForceFeedbackMotor,
+ ARRAY_SIZE(RuntimeClass_Windows_Gaming_Input_ForceFeedback_ForceFeedbackMotor),
+ class_name );
+}
+
+static HRESULT WINAPI motor_GetTrustLevel( IForceFeedbackMotor *iface, TrustLevel *trust_level )
+{
+ FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI motor_get_AreEffectsPaused( IForceFeedbackMotor *iface, BOOLEAN *value )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( iface );
+ DWORD state;
+ HRESULT hr;
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (FAILED(hr = IDirectInputDevice8_GetForceFeedbackState( impl->device, &state ))) *value = FALSE;
+ else *value = (state & DIGFFS_PAUSED);
+
+ return hr;
+}
+
+static HRESULT WINAPI motor_get_MasterGain( IForceFeedbackMotor *iface, double *value )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( iface );
+ DIPROPDWORD gain =
+ {
+ .diph =
+ {
+ .dwSize = sizeof(DIPROPDWORD),
+ .dwHeaderSize = sizeof(DIPROPHEADER),
+ .dwHow = DIPH_DEVICE,
+ },
+ };
+ HRESULT hr;
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (FAILED(hr = IDirectInputDevice8_GetProperty( impl->device, DIPROP_FFGAIN, &gain.diph ))) *value = 1.;
+ else *value = gain.dwData / 10000.;
+
+ return hr;
+}
+
+static HRESULT WINAPI motor_put_MasterGain( IForceFeedbackMotor *iface, double value )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( iface );
+ DIPROPDWORD gain =
+ {
+ .diph =
+ {
+ .dwSize = sizeof(DIPROPDWORD),
+ .dwHeaderSize = sizeof(DIPROPHEADER),
+ .dwHow = DIPH_DEVICE,
+ },
+ };
+
+ TRACE( "iface %p, value %f.\n", iface, value );
+
+ gain.dwData = 10000 * value;
+ return IDirectInputDevice8_SetProperty( impl->device, DIPROP_FFGAIN, &gain.diph );
+}
+
+static HRESULT WINAPI motor_get_IsEnabled( IForceFeedbackMotor *iface, BOOLEAN *value )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( iface );
+ DWORD state;
+ HRESULT hr;
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (FAILED(hr = IDirectInputDevice8_GetForceFeedbackState( impl->device, &state ))) *value = FALSE;
+ else *value = !(state & DIGFFS_ACTUATORSOFF);
+
+ return hr;
+}
+
+static BOOL CALLBACK check_ffb_axes( const DIDEVICEOBJECTINSTANCEW *obj, void *args )
+{
+ ForceFeedbackEffectAxes *value = args;
+
+ if (obj->dwType & DIDFT_FFACTUATOR)
+ {
+ if (IsEqualIID( &obj->guidType, &GUID_XAxis )) *value |= ForceFeedbackEffectAxes_X;
+ else if (IsEqualIID( &obj->guidType, &GUID_YAxis )) *value |= ForceFeedbackEffectAxes_Y;
+ else if (IsEqualIID( &obj->guidType, &GUID_ZAxis )) *value |= ForceFeedbackEffectAxes_Z;
+ }
+
+ return DIENUM_CONTINUE;
+}
+
+static HRESULT WINAPI motor_get_SupportedAxes( IForceFeedbackMotor *iface, enum ForceFeedbackEffectAxes *value )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( iface );
+ HRESULT hr;
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ *value = ForceFeedbackEffectAxes_None;
+ if (FAILED(hr = IDirectInputDevice8_EnumObjects( impl->device, check_ffb_axes, value, DIDFT_AXIS )))
+ *value = ForceFeedbackEffectAxes_None;
+
+ return hr;
+}
+
+static HRESULT WINAPI motor_load_effect_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result )
+{
+ struct effect *effect = impl_from_IForceFeedbackEffect( (IForceFeedbackEffect *)param );
+ IForceFeedbackMotor *motor = (IForceFeedbackMotor *)invoker;
+ struct motor *impl = impl_from_IForceFeedbackMotor( motor );
+ ForceFeedbackEffectAxes supported_axes = 0;
+ IDirectInputEffect *dinput_effect;
+ HRESULT hr;
+
+ EnterCriticalSection( &effect->cs );
+
+ if (FAILED(hr = IForceFeedbackMotor_get_SupportedAxes( motor, &supported_axes )))
+ {
+ WARN( "get_SupportedAxes for motor %p returned %#lx\n", motor, hr );
+ effect->params.cAxes = 0;
+ }
+ else if (effect->params.cAxes == -1)
+ {
+ DWORD count = 0;
+
+ /* initialize axis mapping and re-map directions that were set with the initial mapping */
+ if (supported_axes & ForceFeedbackEffectAxes_X)
+ {
+ effect->directions[count] = effect->directions[0];
+ effect->axes[count++] = DIJOFS_X;
+ }
+ if (supported_axes & ForceFeedbackEffectAxes_Y)
+ {
+ effect->directions[count] = effect->directions[1];
+ effect->axes[count++] = DIJOFS_Y;
+ }
+ if (supported_axes & ForceFeedbackEffectAxes_Z)
+ {
+ effect->directions[count] = effect->directions[2];
+ effect->axes[count++] = DIJOFS_Z;
+ }
+
+ effect->params.cAxes = count;
+ }
+
+ if (SUCCEEDED(hr = IDirectInputDevice8_CreateEffect( impl->device, &effect->type, &effect->params,
+ &dinput_effect, NULL )))
+ {
+ if (effect->effect) IDirectInputEffect_Release( effect->effect );
+ effect->effect = dinput_effect;
+ IDirectInputEffect_AddRef( effect->effect );
+ }
+
+ LeaveCriticalSection( &effect->cs );
+
+ result->vt = VT_UI4;
+ if (SUCCEEDED(hr)) result->ulVal = ForceFeedbackLoadEffectResult_Succeeded;
+ else if (hr == DIERR_DEVICEFULL) result->ulVal = ForceFeedbackLoadEffectResult_EffectStorageFull;
+ else result->ulVal = ForceFeedbackLoadEffectResult_EffectNotSupported;
+
+ return hr;
+}
+
+static HRESULT WINAPI motor_LoadEffectAsync( IForceFeedbackMotor *iface, IForceFeedbackEffect *effect,
+ IAsyncOperation_ForceFeedbackLoadEffectResult **async_op )
+{
+ TRACE( "iface %p, effect %p, async_op %p.\n", iface, effect, async_op );
+ return async_operation_effect_result_create( (IUnknown *)iface, (IUnknown *)effect, motor_load_effect_async, async_op );
+}
+
+static HRESULT WINAPI motor_PauseAllEffects( IForceFeedbackMotor *iface )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( iface );
+
+ TRACE( "iface %p.\n", iface );
+
+ return IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_PAUSE );
+}
+
+static HRESULT WINAPI motor_ResumeAllEffects( IForceFeedbackMotor *iface )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( iface );
+
+ TRACE( "iface %p.\n", iface );
+
+ return IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_CONTINUE );
+}
+
+static HRESULT WINAPI motor_StopAllEffects( IForceFeedbackMotor *iface )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( iface );
+
+ TRACE( "iface %p.\n", iface );
+
+ return IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_STOPALL );
+}
+
+static HRESULT WINAPI motor_try_disable_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)invoker );
+ HRESULT hr;
+
+ hr = IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_SETACTUATORSOFF );
+ result->vt = VT_BOOL;
+ result->boolVal = SUCCEEDED(hr);
+
+ return hr;
+}
+
+static HRESULT WINAPI motor_TryDisableAsync( IForceFeedbackMotor *iface, IAsyncOperation_boolean **async_op )
+{
+ TRACE( "iface %p, async_op %p.\n", iface, async_op );
+ return async_operation_boolean_create( (IUnknown *)iface, NULL, motor_try_disable_async, async_op );
+}
+
+static HRESULT WINAPI motor_try_enable_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)invoker );
+ HRESULT hr;
+
+ hr = IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_SETACTUATORSON );
+ result->vt = VT_BOOL;
+ result->boolVal = SUCCEEDED(hr);
+
+ return hr;
+}
+
+static HRESULT WINAPI motor_TryEnableAsync( IForceFeedbackMotor *iface, IAsyncOperation_boolean **async_op )
+{
+ TRACE( "iface %p, async_op %p.\n", iface, async_op );
+ return async_operation_boolean_create( (IUnknown *)iface, NULL, motor_try_enable_async, async_op );
+}
+
+static HRESULT WINAPI motor_try_reset_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result )
+{
+ struct motor *impl = impl_from_IForceFeedbackMotor( (IForceFeedbackMotor *)invoker );
+ HRESULT hr;
+
+ hr = IDirectInputDevice8_SendForceFeedbackCommand( impl->device, DISFFC_RESET );
+ result->vt = VT_BOOL;
+ result->boolVal = SUCCEEDED(hr);
+
+ return hr;
+}
+
+static HRESULT WINAPI motor_TryResetAsync( IForceFeedbackMotor *iface, IAsyncOperation_boolean **async_op )
+{
+ TRACE( "iface %p, async_op %p.\n", iface, async_op );
+ return async_operation_boolean_create( (IUnknown *)iface, NULL, motor_try_reset_async, async_op );
+}
+
+static HRESULT WINAPI motor_unload_effect_async( IUnknown *iface, IUnknown *param, PROPVARIANT *result )
+{
+ struct effect *effect = impl_from_IForceFeedbackEffect( (IForceFeedbackEffect *)param );
+ IDirectInputEffect *dinput_effect;
+ HRESULT hr;
+
+ EnterCriticalSection( &effect->cs );
+ dinput_effect = effect->effect;
+ effect->effect = NULL;
+ LeaveCriticalSection( &effect->cs );
+
+ if (!dinput_effect) hr = S_OK;
+ else
+ {
+ hr = IDirectInputEffect_Unload( dinput_effect );
+ IDirectInputEffect_Release( dinput_effect );
+ }
+
+ result->vt = VT_BOOL;
+ result->boolVal = SUCCEEDED(hr);
+ return hr;
+}
+
+static HRESULT WINAPI motor_TryUnloadEffectAsync( IForceFeedbackMotor *iface, IForceFeedbackEffect *effect,
+ IAsyncOperation_boolean **async_op )
+{
+ struct effect *impl = impl_from_IForceFeedbackEffect( (IForceFeedbackEffect *)effect );
+ HRESULT hr = S_OK;
+
+ TRACE( "iface %p, effect %p, async_op %p.\n", iface, effect, async_op );
+
+ EnterCriticalSection( &impl->cs );
+ if (!impl->effect) hr = E_FAIL;
+ LeaveCriticalSection( &impl->cs );
+ if (FAILED(hr)) return hr;
+
+ return async_operation_boolean_create( (IUnknown *)iface, (IUnknown *)effect, motor_unload_effect_async, async_op );
+}
+
+static const struct IForceFeedbackMotorVtbl motor_vtbl =
+{
+ motor_QueryInterface,
+ motor_AddRef,
+ motor_Release,
+ /* IInspectable methods */
+ motor_GetIids,
+ motor_GetRuntimeClassName,
+ motor_GetTrustLevel,
+ /* IForceFeedbackMotor methods */
+ motor_get_AreEffectsPaused,
+ motor_get_MasterGain,
+ motor_put_MasterGain,
+ motor_get_IsEnabled,
+ motor_get_SupportedAxes,
+ motor_LoadEffectAsync,
+ motor_PauseAllEffects,
+ motor_ResumeAllEffects,
+ motor_StopAllEffects,
+ motor_TryDisableAsync,
+ motor_TryEnableAsync,
+ motor_TryResetAsync,
+ motor_TryUnloadEffectAsync,
+};
+
+HRESULT force_feedback_motor_create( IDirectInputDevice8W *device, IForceFeedbackMotor **out )
+{
+ struct motor *impl;
+ HRESULT hr;
+
+ TRACE( "device %p, out %p\n", device, out );
+
+ if (FAILED(hr = IDirectInputDevice8_Unacquire( device ))) goto failed;
+ if (FAILED(hr = IDirectInputDevice8_SetCooperativeLevel( device, GetDesktopWindow(), DISCL_BACKGROUND | DISCL_EXCLUSIVE ))) goto failed;
+ if (FAILED(hr = IDirectInputDevice8_Acquire( device ))) goto failed;
+
+ if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
+ impl->IForceFeedbackMotor_iface.lpVtbl = &motor_vtbl;
+ impl->ref = 1;
+
+ IDirectInputDevice_AddRef( device );
+ impl->device = device;
+
+ *out = &impl->IForceFeedbackMotor_iface;
+ TRACE( "created ForceFeedbackMotor %p\n", *out );
+ return S_OK;
+
+failed:
+ IDirectInputDevice8_SetCooperativeLevel( device, 0, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE );
+ IDirectInputDevice8_Acquire( device );
+ WARN( "Failed to acquire device exclusively, hr %#lx\n", hr );
+ return hr;
+}
diff --git a/dlls/windows.gaming.input/gamepad.c b/dlls/windows.gaming.input/gamepad.c
index 0c38fb5cd1a..8dab9a62d09 100644
--- wine/dlls/windows.gaming.input/gamepad.c
+++ wine/dlls/windows.gaming.input/gamepad.c
@@ -61,6 +61,7 @@ struct gamepad
IGameControllerImpl IGameControllerImpl_iface;
IGameControllerInputSink IGameControllerInputSink_iface;
IGamepad IGamepad_iface;
+ IGamepad2 IGamepad2_iface;
IGameController *IGameController_outer;
LONG ref;
@@ -99,7 +100,13 @@ static HRESULT WINAPI controller_QueryInterface( IGameControllerImpl *iface, REF
return S_OK;
}
- WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ if (IsEqualGUID( iid, &IID_IGamepad2 ))
+ {
+ IInspectable_AddRef( (*out = &impl->IGamepad2_iface) );
+ return S_OK;
+ }
+
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
*out = NULL;
return E_NOINTERFACE;
}
@@ -330,6 +337,28 @@ static const struct IGamepadVtbl gamepad_vtbl =
gamepad_GetCurrentReading,
};
+DEFINE_IINSPECTABLE_OUTER( gamepad2, IGamepad2, struct gamepad, IGameController_outer )
+
+static HRESULT WINAPI gamepad2_GetButtonLabel(IGamepad2 *iface, GamepadButtons button, GameControllerButtonLabel *value)
+{
+ FIXME( "iface %p, button %#x, value %p stub!\n", iface, button, value );
+ *value = GameControllerButtonLabel_None;
+ return S_OK;
+}
+
+static const struct IGamepad2Vtbl gamepad2_vtbl =
+{
+ gamepad2_QueryInterface,
+ gamepad2_AddRef,
+ gamepad2_Release,
+ /* IInspectable methods */
+ gamepad2_GetIids,
+ gamepad2_GetRuntimeClassName,
+ gamepad2_GetTrustLevel,
+ /* IGamepad2 methods */
+ gamepad2_GetButtonLabel,
+};
+
struct gamepad_statics
{
IActivationFactory IActivationFactory_iface;
@@ -542,6 +571,7 @@ static HRESULT WINAPI controller_factory_CreateGameController( ICustomGameContro
impl->IGameControllerImpl_iface.lpVtbl = &controller_vtbl;
impl->IGameControllerInputSink_iface.lpVtbl = &input_sink_vtbl;
impl->IGamepad_iface.lpVtbl = &gamepad_vtbl;
+ impl->IGamepad2_iface.lpVtbl = &gamepad2_vtbl;
impl->ref = 1;
TRACE( "created Gamepad %p\n", impl );
diff --git a/dlls/windows.gaming.input/main.c b/dlls/windows.gaming.input/main.c
index 21808d9c2ad..a20630cd20b 100644
--- wine/dlls/windows.gaming.input/main.c
+++ wine/dlls/windows.gaming.input/main.c
@@ -185,6 +185,15 @@ HRESULT WINAPI DllGetActivationFactory( HSTRING class_str, IActivationFactory **
if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_Custom_GameControllerFactoryManager ))
IGameControllerFactoryManagerStatics2_QueryInterface( manager_factory, &IID_IActivationFactory, (void **)factory );
+ if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_ForceFeedback_ConstantForceEffect ))
+ IInspectable_QueryInterface( constant_effect_factory, &IID_IActivationFactory, (void **)factory );
+ if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_ForceFeedback_RampForceEffect ))
+ IInspectable_QueryInterface( ramp_effect_factory, &IID_IActivationFactory, (void **)factory );
+ if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_ForceFeedback_PeriodicForceEffect ))
+ IInspectable_QueryInterface( periodic_effect_factory, &IID_IActivationFactory, (void **)factory );
+ if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_ForceFeedback_ConditionForceEffect ))
+ IInspectable_QueryInterface( condition_effect_factory, &IID_IActivationFactory, (void **)factory );
+
if (*factory) return S_OK;
return CLASS_E_CLASSNOTAVAILABLE;
}
diff --git a/dlls/windows.gaming.input/periodic_effect.c b/dlls/windows.gaming.input/periodic_effect.c
new file mode 100644
index 00000000000..8633a8fb9b9
--- /dev/null
+++ wine/dlls/windows.gaming.input/periodic_effect.c
@@ -0,0 +1,326 @@
+/* WinRT Windows.Gaming.Input implementation
+ *
+ * Copyright 2022 Rémi Bernon for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "private.h"
+#include "provider.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(input);
+
+struct periodic_effect
+{
+ IPeriodicForceEffect IPeriodicForceEffect_iface;
+ IWineForceFeedbackEffectImpl *IWineForceFeedbackEffectImpl_inner;
+ LONG ref;
+
+ PeriodicForceEffectKind kind;
+};
+
+static inline struct periodic_effect *impl_from_IPeriodicForceEffect( IPeriodicForceEffect *iface )
+{
+ return CONTAINING_RECORD( iface, struct periodic_effect, IPeriodicForceEffect_iface );
+}
+
+static HRESULT WINAPI effect_QueryInterface( IPeriodicForceEffect *iface, REFIID iid, void **out )
+{
+ struct periodic_effect *impl = impl_from_IPeriodicForceEffect( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IPeriodicForceEffect ))
+ {
+ IInspectable_AddRef( (*out = &impl->IPeriodicForceEffect_iface) );
+ return S_OK;
+ }
+
+ return IWineForceFeedbackEffectImpl_QueryInterface( impl->IWineForceFeedbackEffectImpl_inner, iid, out );
+}
+
+static ULONG WINAPI effect_AddRef( IPeriodicForceEffect *iface )
+{
+ struct periodic_effect *impl = impl_from_IPeriodicForceEffect( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI effect_Release( IPeriodicForceEffect *iface )
+{
+ struct periodic_effect *impl = impl_from_IPeriodicForceEffect( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+
+ TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+
+ if (!ref)
+ {
+ /* guard against re-entry if inner releases an outer iface */
+ InterlockedIncrement( &impl->ref );
+ IWineForceFeedbackEffectImpl_Release( impl->IWineForceFeedbackEffectImpl_inner );
+ free( impl );
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI effect_GetIids( IPeriodicForceEffect *iface, ULONG *iid_count, IID **iids )
+{
+ FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI effect_GetRuntimeClassName( IPeriodicForceEffect *iface, HSTRING *class_name )
+{
+ return WindowsCreateString( RuntimeClass_Windows_Gaming_Input_ForceFeedback_PeriodicForceEffect,
+ ARRAY_SIZE(RuntimeClass_Windows_Gaming_Input_ForceFeedback_PeriodicForceEffect),
+ class_name );
+}
+
+static HRESULT WINAPI effect_GetTrustLevel( IPeriodicForceEffect *iface, TrustLevel *trust_level )
+{
+ FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI effect_get_Kind( IPeriodicForceEffect *iface, PeriodicForceEffectKind *kind )
+{
+ struct periodic_effect *impl = impl_from_IPeriodicForceEffect( iface );
+ TRACE( "iface %p, kind %p.\n", iface, kind );
+ *kind = impl->kind;
+ return S_OK;
+}
+
+static HRESULT WINAPI effect_SetParameters( IPeriodicForceEffect *iface, Vector3 direction, FLOAT frequency, FLOAT phase,
+ FLOAT bias, TimeSpan duration )
+{
+ struct periodic_effect *impl = impl_from_IPeriodicForceEffect( iface );
+ WineForceFeedbackEffectParameters params =
+ {
+ .periodic =
+ {
+ .type = WineForceFeedbackEffectType_Periodic_SquareWave + impl->kind,
+ .direction = direction,
+ .frequency = frequency,
+ .phase = phase,
+ .bias = bias,
+ .duration = duration,
+ .repeat_count = 1,
+ .gain = 1.,
+ },
+ };
+
+ TRACE( "iface %p, direction %s, frequency %f, phase %f, bias %f, duration %I64u.\n", iface,
+ debugstr_vector3( &direction ), frequency, phase, bias, duration.Duration );
+
+ return IWineForceFeedbackEffectImpl_put_Parameters( impl->IWineForceFeedbackEffectImpl_inner, params, NULL );
+}
+
+static HRESULT WINAPI effect_SetParametersWithEnvelope( IPeriodicForceEffect *iface, Vector3 direction, FLOAT frequency, FLOAT phase, FLOAT bias,
+ FLOAT attack_gain, FLOAT sustain_gain, FLOAT release_gain, TimeSpan start_delay,
+ TimeSpan attack_duration, TimeSpan sustain_duration,
+ TimeSpan release_duration, UINT32 repeat_count )
+{
+ struct periodic_effect *impl = impl_from_IPeriodicForceEffect( iface );
+ WineForceFeedbackEffectParameters params =
+ {
+ .periodic =
+ {
+ .type = WineForceFeedbackEffectType_Periodic_SquareWave + impl->kind,
+ .direction = direction,
+ .frequency = frequency,
+ .phase = phase,
+ .bias = bias,
+ .duration = {attack_duration.Duration + sustain_duration.Duration + release_duration.Duration},
+ .start_delay = start_delay,
+ .repeat_count = repeat_count,
+ .gain = sustain_gain,
+ },
+ };
+ WineForceFeedbackEffectEnvelope envelope =
+ {
+ .attack_gain = attack_gain,
+ .release_gain = release_gain,
+ .attack_duration = attack_duration,
+ .release_duration = release_duration,
+ };
+
+ TRACE( "iface %p, direction %s, frequency %f, phase %f, bias %f, attack_gain %f, sustain_gain %f, release_gain %f, start_delay %I64u, "
+ "attack_duration %I64u, sustain_duration %I64u, release_duration %I64u, repeat_count %u.\n", iface, debugstr_vector3( &direction ),
+ frequency, phase, bias, attack_gain, sustain_gain, release_gain, start_delay.Duration, attack_duration.Duration, sustain_duration.Duration,
+ release_duration.Duration, repeat_count );
+
+ return IWineForceFeedbackEffectImpl_put_Parameters( impl->IWineForceFeedbackEffectImpl_inner, params, &envelope );
+}
+
+static const struct IPeriodicForceEffectVtbl effect_vtbl =
+{
+ effect_QueryInterface,
+ effect_AddRef,
+ effect_Release,
+ /* IInspectable methods */
+ effect_GetIids,
+ effect_GetRuntimeClassName,
+ effect_GetTrustLevel,
+ /* IPeriodicForceEffect methods */
+ effect_get_Kind,
+ effect_SetParameters,
+ effect_SetParametersWithEnvelope,
+};
+
+struct periodic_factory
+{
+ IActivationFactory IActivationFactory_iface;
+ IPeriodicForceEffectFactory IPeriodicForceEffectFactory_iface;
+ LONG ref;
+};
+
+static inline struct periodic_factory *impl_from_IActivationFactory( IActivationFactory *iface )
+{
+ return CONTAINING_RECORD( iface, struct periodic_factory, IActivationFactory_iface );
+}
+
+static HRESULT WINAPI activation_QueryInterface( IActivationFactory *iface, REFIID iid, void **out )
+{
+ struct periodic_factory *impl = impl_from_IActivationFactory( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IActivationFactory ))
+ {
+ IInspectable_AddRef( (*out = &impl->IActivationFactory_iface) );
+ return S_OK;
+ }
+
+ if (IsEqualGUID( iid, &IID_IPeriodicForceEffectFactory ))
+ {
+ IInspectable_AddRef( (*out = &impl->IPeriodicForceEffectFactory_iface) );
+ return S_OK;
+ }
+
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI activation_AddRef( IActivationFactory *iface )
+{
+ struct periodic_factory *impl = impl_from_IActivationFactory( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI activation_Release( IActivationFactory *iface )
+{
+ struct periodic_factory *impl = impl_from_IActivationFactory( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+ TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static HRESULT WINAPI activation_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids )
+{
+ FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI activation_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name )
+{
+ FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI activation_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level )
+{
+ FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI activation_ActivateInstance( IActivationFactory *iface, IInspectable **instance )
+{
+ FIXME( "iface %p, instance %p stub!\n", iface, instance );
+ return E_NOTIMPL;
+}
+
+static const struct IActivationFactoryVtbl activation_vtbl =
+{
+ activation_QueryInterface,
+ activation_AddRef,
+ activation_Release,
+ /* IInspectable methods */
+ activation_GetIids,
+ activation_GetRuntimeClassName,
+ activation_GetTrustLevel,
+ /* IActivationFactory methods */
+ activation_ActivateInstance,
+};
+
+DEFINE_IINSPECTABLE( factory, IPeriodicForceEffectFactory, struct periodic_factory, IActivationFactory_iface )
+
+static HRESULT WINAPI factory_CreateInstance( IPeriodicForceEffectFactory *iface, enum PeriodicForceEffectKind kind, IForceFeedbackEffect **out )
+{
+ enum WineForceFeedbackEffectType type = WineForceFeedbackEffectType_Periodic + kind;
+ struct periodic_effect *impl;
+ HRESULT hr;
+
+ TRACE( "iface %p, kind %u, out %p.\n", iface, kind, out );
+
+ if (!(impl = calloc( 1, sizeof(struct periodic_effect) ))) return E_OUTOFMEMORY;
+ impl->IPeriodicForceEffect_iface.lpVtbl = &effect_vtbl;
+ impl->ref = 1;
+ impl->kind = kind;
+
+ if (FAILED(hr = force_feedback_effect_create( type, (IInspectable *)&impl->IPeriodicForceEffect_iface, &impl->IWineForceFeedbackEffectImpl_inner )) ||
+ FAILED(hr = IPeriodicForceEffect_QueryInterface( &impl->IPeriodicForceEffect_iface, &IID_IForceFeedbackEffect, (void **)out )))
+ {
+ if (impl->IWineForceFeedbackEffectImpl_inner) IWineForceFeedbackEffectImpl_Release( impl->IWineForceFeedbackEffectImpl_inner );
+ free( impl );
+ return hr;
+ }
+
+ IPeriodicForceEffect_Release( &impl->IPeriodicForceEffect_iface );
+ TRACE( "created PeriodicForceEffect %p\n", *out );
+ return S_OK;
+}
+
+static const struct IPeriodicForceEffectFactoryVtbl factory_vtbl =
+{
+ factory_QueryInterface,
+ factory_AddRef,
+ factory_Release,
+ /* IInspectable methods */
+ factory_GetIids,
+ factory_GetRuntimeClassName,
+ factory_GetTrustLevel,
+ /* IPeriodicForceEffectFactory methods */
+ factory_CreateInstance,
+};
+
+static struct periodic_factory periodic_statics =
+{
+ {&activation_vtbl},
+ {&factory_vtbl},
+ 1,
+};
+
+IInspectable *periodic_effect_factory = (IInspectable *)&periodic_statics.IActivationFactory_iface;
diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h
index 58b2040d3de..f53d5b5bc37 100644
--- wine/dlls/windows.gaming.input/private.h
+++ wine/dlls/windows.gaming.input/private.h
@@ -25,11 +25,13 @@
#include "winbase.h"
#include "winstring.h"
#include "objbase.h"
+#include "dinput.h"
#include "activation.h"
#define WIDL_using_Windows_Foundation
#define WIDL_using_Windows_Foundation_Collections
+#define WIDL_using_Windows_Foundation_Numerics
#include "windows.foundation.h"
#define WIDL_using_Windows_Devices_Power
#define WIDL_using_Windows_Gaming_Input
@@ -37,13 +39,20 @@
#define WIDL_using_Windows_Gaming_Input_ForceFeedback
#include "windows.gaming.input.custom.h"
+#include "wine/debug.h"
#include "wine/list.h"
+#include "provider.h"
+
extern HINSTANCE windows_gaming_input;
extern ICustomGameControllerFactory *controller_factory;
extern ICustomGameControllerFactory *gamepad_factory;
extern ICustomGameControllerFactory *racing_wheel_factory;
extern IGameControllerFactoryManagerStatics2 *manager_factory;
+extern IInspectable *constant_effect_factory;
+extern IInspectable *ramp_effect_factory;
+extern IInspectable *periodic_effect_factory;
+extern IInspectable *condition_effect_factory;
struct vector_iids
{
@@ -64,6 +73,15 @@ extern HRESULT event_handlers_append( struct list *list, IEventHandler_IInspecta
extern HRESULT event_handlers_remove( struct list *list, EventRegistrationToken *token );
extern void event_handlers_notify( struct list *list, IInspectable *element );
+extern HRESULT force_feedback_motor_create( IDirectInputDevice8W *device, IForceFeedbackMotor **out );
+extern HRESULT force_feedback_effect_create( enum WineForceFeedbackEffectType type, IInspectable *outer, IWineForceFeedbackEffectImpl **out );
+
+typedef HRESULT (WINAPI *async_operation_callback)( IUnknown *invoker, IUnknown *param, PROPVARIANT *result );
+extern HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback,
+ IAsyncOperation_boolean **out );
+extern HRESULT async_operation_effect_result_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback,
+ IAsyncOperation_ForceFeedbackLoadEffectResult **out );
+
#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \
static inline impl_type *impl_from( iface_type *iface ) \
{ \
@@ -103,3 +121,9 @@ extern void event_handlers_notify( struct list *list, IInspectable *element );
DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface )
#define DEFINE_IINSPECTABLE_OUTER( pfx, iface_type, impl_type, outer_iface ) \
DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, impl->outer_iface )
+
+static inline const char *debugstr_vector3( const Vector3 *vector )
+{
+ if (!vector) return "(null)";
+ return wine_dbg_sprintf( "[%f, %f, %f]", vector->X, vector->Y, vector->Z );
+}
diff --git a/dlls/windows.gaming.input/provider.c b/dlls/windows.gaming.input/provider.c
index 69098e8abb6..d0472727224 100644
--- wine/dlls/windows.gaming.input/provider.c
+++ wine/dlls/windows.gaming.input/provider.c
@@ -141,21 +141,37 @@ static HRESULT WINAPI wine_provider_GetTrustLevel( IWineGameControllerProvider *
return E_NOTIMPL;
}
+static BOOL CALLBACK count_ffb_axes( const DIDEVICEOBJECTINSTANCEW *obj, void *args )
+{
+ DWORD *count = args;
+ if (obj->dwType & DIDFT_FFACTUATOR) (*count)++;
+ return DIENUM_CONTINUE;
+}
+
static HRESULT WINAPI wine_provider_get_Type( IWineGameControllerProvider *iface, WineGameControllerType *value )
{
struct provider *impl = impl_from_IWineGameControllerProvider( iface );
DIDEVICEINSTANCEW instance = {.dwSize = sizeof(DIDEVICEINSTANCEW)};
+ const WCHAR *tmp;
HRESULT hr;
TRACE( "iface %p, value %p.\n", iface, value );
if (FAILED(hr = IDirectInputDevice8_GetDeviceInfo( impl->dinput_device, &instance ))) return hr;
- switch (GET_DIDEVICE_TYPE( instance.dwDevType ))
+ if ((tmp = wcschr( impl->device_path + 8, '#' )) && !wcsnicmp( tmp - 6, L"&XI_", 4 ))
+ *value = WineGameControllerType_Gamepad;
+ else switch (GET_DIDEVICE_TYPE( instance.dwDevType ))
{
case DI8DEVTYPE_DRIVING: *value = WineGameControllerType_RacingWheel; break;
- case DI8DEVTYPE_GAMEPAD: *value = WineGameControllerType_Gamepad; break;
- default: *value = WineGameControllerType_Joystick; break;
+ default:
+ {
+ DWORD count = 0;
+ hr = IDirectInputDevice8_EnumObjects( impl->dinput_device, count_ffb_axes, &count, DIDFT_AXIS );
+ if (SUCCEEDED(hr) && count == 1) *value = WineGameControllerType_RacingWheel;
+ else *value = WineGameControllerType_Joystick;
+ break;
+ }
}
return S_OK;
@@ -212,7 +228,7 @@ static HRESULT WINAPI wine_provider_get_State( IWineGameControllerProvider *ifac
if (FAILED(hr = IDirectInputDevice8_GetDeviceState( impl->dinput_device, sizeof(state), &state )))
{
WARN( "Failed to read device state, hr %#lx\n", hr );
- return hr;
+ return S_OK;
}
i = ARRAY_SIZE(state.rgbButtons);
@@ -315,6 +331,21 @@ static HRESULT WINAPI wine_provider_put_Vibration( IWineGameControllerProvider *
return S_OK;
}
+static HRESULT WINAPI wine_provider_get_ForceFeedbackMotor( IWineGameControllerProvider *iface, IForceFeedbackMotor **value )
+{
+ struct provider *impl = impl_from_IWineGameControllerProvider( iface );
+ DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)};
+ HRESULT hr;
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (SUCCEEDED(hr = IDirectInputDevice8_GetCapabilities( impl->dinput_device, &caps )) && (caps.dwFlags & DIDC_FORCEFEEDBACK))
+ return force_feedback_motor_create( impl->dinput_device, value );
+
+ *value = NULL;
+ return S_OK;
+}
+
static const struct IWineGameControllerProviderVtbl wine_provider_vtbl =
{
wine_provider_QueryInterface,
@@ -332,6 +363,7 @@ static const struct IWineGameControllerProviderVtbl wine_provider_vtbl =
wine_provider_get_State,
wine_provider_get_Vibration,
wine_provider_put_Vibration,
+ wine_provider_get_ForceFeedbackMotor,
};
DEFINE_IINSPECTABLE( game_provider, IGameControllerProvider, struct provider, IWineGameControllerProvider_iface )
@@ -556,7 +588,7 @@ void provider_create( const WCHAR *device_path )
EnterCriticalSection( &provider_cs );
LIST_FOR_EACH_ENTRY( entry, &provider_list, struct provider, entry )
- if ((found = !wcscmp( entry->device_path, device_path ))) break;
+ if ((found = !wcsicmp( entry->device_path, device_path ))) break;
if (!found) list_add_tail( &provider_list, &impl->entry );
LeaveCriticalSection( &provider_cs );
@@ -576,11 +608,12 @@ void provider_remove( const WCHAR *device_path )
EnterCriticalSection( &provider_cs );
LIST_FOR_EACH_ENTRY( entry, &provider_list, struct provider, entry )
- if ((found = !wcscmp( entry->device_path, device_path ))) break;
+ if ((found = !wcsicmp( entry->device_path, device_path ))) break;
if (found) list_remove( &entry->entry );
LeaveCriticalSection( &provider_cs );
- if (found)
+ if (!found) WARN( "provider not found for device %s\n", debugstr_w( device_path ) );
+ else
{
provider = &entry->IGameControllerProvider_iface;
manager_on_provider_removed( provider );
diff --git a/dlls/windows.gaming.input/provider.idl b/dlls/windows.gaming.input/provider.idl
index 865a149eaa5..e7b6e96b8aa 100644
--- wine/dlls/windows.gaming.input/provider.idl
+++ wine/dlls/windows.gaming.input/provider.idl
@@ -22,6 +22,7 @@
#pragma winrt ns_prefix
#endif
+import "propidl.idl";
import "inspectable.idl";
import "asyncinfo.idl";
import "eventtoken.idl";
@@ -29,14 +30,25 @@ import "windowscontracts.idl";
import "windows.foundation.idl";
import "windows.gaming.input.idl";
import "windows.gaming.input.custom.idl";
+import "windows.gaming.input.forcefeedback.idl";
namespace Windows.Gaming.Input.Custom {
typedef enum WineGameControllerType WineGameControllerType;
+ typedef enum WineForceFeedbackEffectType WineForceFeedbackEffectType;
typedef struct WineGameControllerState WineGameControllerState;
typedef struct WineGameControllerVibration WineGameControllerVibration;
+ typedef struct WineConditionEffectParameters WineConditionEffectParameters;
+ typedef struct WineConstantEffectParameters WineConstantEffectParameters;
+ typedef struct WineRampEffectParameters WineRampEffectParameters;
+ typedef struct WinePeriodicEffectParameters WinePeriodicEffectParameters;
+ typedef struct WineForceFeedbackEffectEnvelope WineForceFeedbackEffectEnvelope;
+ typedef union WineForceFeedbackEffectParameters WineForceFeedbackEffectParameters;
interface IWineGameControllerProvider;
runtimeclass WineGameControllerProvider;
+ /* type-pruning version of AsyncOperationCompletedHandler<T> */
+ delegate HRESULT WineAsyncOperationCompletedHandler([in] IInspectable *async, [in] AsyncStatus status);
+
enum WineGameControllerType
{
Joystick = 0,
@@ -44,6 +56,27 @@ namespace Windows.Gaming.Input.Custom {
RacingWheel = 2,
};
+ enum WineForceFeedbackEffectType
+ {
+ Constant = 1,
+ Ramp = 2,
+
+ Periodic = 10,
+ /* same order as PeriodicForceEffectKind */
+ Periodic_SquareWave = 10,
+ Periodic_SineWave = 11,
+ Periodic_TriangleWave = 12,
+ Periodic_SawtoothWaveUp = 13,
+ Periodic_SawtoothWaveDown = 14,
+
+ Condition = 20,
+ /* same order as ConditionForceEffectKind */
+ Condition_Spring = 20,
+ Condition_Damper = 21,
+ Condition_Inertia = 22,
+ Condition_Friction = 23,
+ };
+
struct WineGameControllerState
{
UINT64 timestamp;
@@ -60,6 +93,69 @@ namespace Windows.Gaming.Input.Custom {
UINT16 right;
};
+ struct WineConditionEffectParameters
+ {
+ WineForceFeedbackEffectType type;
+ Windows.Foundation.Numerics.Vector3 direction;
+ FLOAT positive_coeff;
+ FLOAT negative_coeff;
+ FLOAT max_positive_magnitude;
+ FLOAT max_negative_magnitude;
+ FLOAT deadzone;
+ FLOAT bias;
+ };
+
+ struct WineConstantEffectParameters
+ {
+ WineForceFeedbackEffectType type;
+ Windows.Foundation.Numerics.Vector3 direction;
+ Windows.Foundation.TimeSpan duration;
+ Windows.Foundation.TimeSpan start_delay;
+ UINT32 repeat_count;
+ FLOAT gain;
+ };
+
+ struct WineRampEffectParameters
+ {
+ WineForceFeedbackEffectType type;
+ Windows.Foundation.Numerics.Vector3 start_vector;
+ Windows.Foundation.Numerics.Vector3 end_vector;
+ Windows.Foundation.TimeSpan duration;
+ Windows.Foundation.TimeSpan start_delay;
+ UINT32 repeat_count;
+ FLOAT gain;
+ };
+
+ struct WinePeriodicEffectParameters
+ {
+ WineForceFeedbackEffectType type;
+ Windows.Foundation.Numerics.Vector3 direction;
+ Windows.Foundation.TimeSpan duration;
+ Windows.Foundation.TimeSpan start_delay;
+ UINT32 repeat_count;
+ FLOAT frequency;
+ FLOAT phase;
+ FLOAT bias;
+ FLOAT gain;
+ };
+
+ struct WineForceFeedbackEffectEnvelope
+ {
+ FLOAT attack_gain;
+ FLOAT release_gain;
+ Windows.Foundation.TimeSpan attack_duration;
+ Windows.Foundation.TimeSpan release_duration;
+ };
+
+ union WineForceFeedbackEffectParameters
+ {
+ WineForceFeedbackEffectType type;
+ WineConditionEffectParameters condition;
+ WineConstantEffectParameters constant;
+ WineRampEffectParameters ramp;
+ WinePeriodicEffectParameters periodic;
+ };
+
[
uuid(06e58977-7684-4dc5-bad1-cda52a4aa06d)
]
@@ -85,6 +181,29 @@ namespace Windows.Gaming.Input.Custom {
[propget] HRESULT State([out, retval] WineGameControllerState *state);
[propget] HRESULT Vibration([out, retval] WineGameControllerVibration *vibration);
[propput] HRESULT Vibration([in] WineGameControllerVibration vibration);
+
+ [propget] HRESULT ForceFeedbackMotor([out, retval] Windows.Gaming.Input.ForceFeedback.ForceFeedbackMotor **motor);
+ }
+
+ [
+ uuid(27833469-7760-417e-adbe-e011a66e16ee)
+ ]
+ interface IWineForceFeedbackEffectImpl : IUnknown
+ requires Windows.Gaming.Input.ForceFeedback.IForceFeedbackEffect
+ {
+ [propput] HRESULT Parameters([in] WineForceFeedbackEffectParameters parameters,
+ [in, optional] WineForceFeedbackEffectEnvelope *envelope);
+ }
+
+ [
+ uuid(83f377ee-c799-11ec-9d64-0242ac120002)
+ ]
+ interface IWineAsyncInfoImpl : IUnknown
+ {
+ [propput] HRESULT Completed([in] WineAsyncOperationCompletedHandler *handler);
+ [propget] HRESULT Completed([out, retval] WineAsyncOperationCompletedHandler **handler);
+ [propget] HRESULT Result([out, retval] PROPVARIANT *result);
+ HRESULT Start();
}
[
diff --git a/dlls/windows.gaming.input/racing_wheel.c b/dlls/windows.gaming.input/racing_wheel.c
index b4635d03153..d646ca26c03 100644
--- wine/dlls/windows.gaming.input/racing_wheel.c
+++ wine/dlls/windows.gaming.input/racing_wheel.c
@@ -99,7 +99,7 @@ static HRESULT WINAPI controller_QueryInterface( IGameControllerImpl *iface, REF
return S_OK;
}
- WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
*out = NULL;
return E_NOINTERFACE;
}
@@ -245,8 +245,11 @@ static HRESULT WINAPI racing_wheel_get_MaxWheelAngle( IRacingWheel *iface, DOUBL
static HRESULT WINAPI racing_wheel_get_WheelMotor( IRacingWheel *iface, IForceFeedbackMotor **value )
{
- FIXME( "iface %p, value %p stub!\n", iface, value );
- return E_NOTIMPL;
+ struct racing_wheel *impl = impl_from_IRacingWheel( iface );
+
+ TRACE( "iface %p, value %p\n", iface, value );
+
+ return IWineGameControllerProvider_get_ForceFeedbackMotor( impl->wine_provider, value );
}
static HRESULT WINAPI racing_wheel_GetButtonLabel( IRacingWheel *iface, enum RacingWheelButtons button,
diff --git a/dlls/windows.gaming.input/ramp_effect.c b/dlls/windows.gaming.input/ramp_effect.c
new file mode 100644
index 00000000000..fadcf151c04
--- /dev/null
+++ wine/dlls/windows.gaming.input/ramp_effect.c
@@ -0,0 +1,278 @@
+/* WinRT Windows.Gaming.Input implementation
+ *
+ * Copyright 2022 Rémi Bernon for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "private.h"
+#include "provider.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(input);
+
+struct ramp_effect
+{
+ IRampForceEffect IRampForceEffect_iface;
+ IWineForceFeedbackEffectImpl *IWineForceFeedbackEffectImpl_inner;
+ LONG ref;
+};
+
+static inline struct ramp_effect *impl_from_IRampForceEffect( IRampForceEffect *iface )
+{
+ return CONTAINING_RECORD( iface, struct ramp_effect, IRampForceEffect_iface );
+}
+
+static HRESULT WINAPI effect_QueryInterface( IRampForceEffect *iface, REFIID iid, void **out )
+{
+ struct ramp_effect *impl = impl_from_IRampForceEffect( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IRampForceEffect ))
+ {
+ IInspectable_AddRef( (*out = &impl->IRampForceEffect_iface) );
+ return S_OK;
+ }
+
+ return IWineForceFeedbackEffectImpl_QueryInterface( impl->IWineForceFeedbackEffectImpl_inner, iid, out );
+}
+
+static ULONG WINAPI effect_AddRef( IRampForceEffect *iface )
+{
+ struct ramp_effect *impl = impl_from_IRampForceEffect( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI effect_Release( IRampForceEffect *iface )
+{
+ struct ramp_effect *impl = impl_from_IRampForceEffect( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+
+ TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+
+ if (!ref)
+ {
+ /* guard against re-entry if inner releases an outer iface */
+ InterlockedIncrement( &impl->ref );
+ IWineForceFeedbackEffectImpl_Release( impl->IWineForceFeedbackEffectImpl_inner );
+ free( impl );
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI effect_GetIids( IRampForceEffect *iface, ULONG *iid_count, IID **iids )
+{
+ FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI effect_GetRuntimeClassName( IRampForceEffect *iface, HSTRING *class_name )
+{
+ return WindowsCreateString( RuntimeClass_Windows_Gaming_Input_ForceFeedback_RampForceEffect,
+ ARRAY_SIZE(RuntimeClass_Windows_Gaming_Input_ForceFeedback_RampForceEffect),
+ class_name );
+}
+
+static HRESULT WINAPI effect_GetTrustLevel( IRampForceEffect *iface, TrustLevel *trust_level )
+{
+ FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI effect_SetParameters( IRampForceEffect *iface, Vector3 start_vector, Vector3 end_vector, TimeSpan duration )
+{
+ WineForceFeedbackEffectParameters params =
+ {
+ .ramp =
+ {
+ .type = WineForceFeedbackEffectType_Ramp,
+ .start_vector = start_vector,
+ .end_vector = end_vector,
+ .duration = duration,
+ .repeat_count = 1,
+ .gain = 1.,
+ },
+ };
+ struct ramp_effect *impl = impl_from_IRampForceEffect( iface );
+
+ TRACE( "iface %p, start_vector %s, end_vector %s, duration %I64u.\n", iface,
+ debugstr_vector3( &start_vector ), debugstr_vector3( &end_vector ), duration.Duration );
+
+ return IWineForceFeedbackEffectImpl_put_Parameters( impl->IWineForceFeedbackEffectImpl_inner, params, NULL );
+}
+
+static HRESULT WINAPI effect_SetParametersWithEnvelope( IRampForceEffect *iface, Vector3 start_vector, Vector3 end_vector, FLOAT attack_gain,
+ FLOAT sustain_gain, FLOAT release_gain, TimeSpan start_delay,
+ TimeSpan attack_duration, TimeSpan sustain_duration,
+ TimeSpan release_duration, UINT32 repeat_count )
+{
+ WineForceFeedbackEffectParameters params =
+ {
+ .ramp =
+ {
+ .type = WineForceFeedbackEffectType_Ramp,
+ .start_vector = start_vector,
+ .end_vector = end_vector,
+ .duration = {attack_duration.Duration + sustain_duration.Duration + release_duration.Duration},
+ .start_delay = start_delay,
+ .repeat_count = repeat_count,
+ .gain = sustain_gain,
+ },
+ };
+ WineForceFeedbackEffectEnvelope envelope =
+ {
+ .attack_gain = attack_gain,
+ .release_gain = release_gain,
+ .attack_duration = attack_duration,
+ .release_duration = release_duration,
+ };
+ struct ramp_effect *impl = impl_from_IRampForceEffect( iface );
+
+ TRACE( "iface %p, start_vector %s, end_vector %s, attack_gain %f, sustain_gain %f, release_gain %f, start_delay %I64u, attack_duration %I64u, "
+ "sustain_duration %I64u, release_duration %I64u, repeat_count %u.\n", iface, debugstr_vector3( &start_vector ), debugstr_vector3( &end_vector ),
+ attack_gain, sustain_gain, release_gain, start_delay.Duration, attack_duration.Duration, sustain_duration.Duration,
+ release_duration.Duration, repeat_count );
+
+ return IWineForceFeedbackEffectImpl_put_Parameters( impl->IWineForceFeedbackEffectImpl_inner, params, &envelope );
+}
+
+static const struct IRampForceEffectVtbl effect_vtbl =
+{
+ effect_QueryInterface,
+ effect_AddRef,
+ effect_Release,
+ /* IInspectable methods */
+ effect_GetIids,
+ effect_GetRuntimeClassName,
+ effect_GetTrustLevel,
+ /* IRampForceEffect methods */
+ effect_SetParameters,
+ effect_SetParametersWithEnvelope,
+};
+
+struct ramp_factory
+{
+ IActivationFactory IActivationFactory_iface;
+ LONG ref;
+};
+
+static inline struct ramp_factory *impl_from_IActivationFactory( IActivationFactory *iface )
+{
+ return CONTAINING_RECORD( iface, struct ramp_factory, IActivationFactory_iface );
+}
+
+static HRESULT WINAPI activation_QueryInterface( IActivationFactory *iface, REFIID iid, void **out )
+{
+ struct ramp_factory *impl = impl_from_IActivationFactory( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IActivationFactory ))
+ {
+ IInspectable_AddRef( (*out = &impl->IActivationFactory_iface) );
+ return S_OK;
+ }
+
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI activation_AddRef( IActivationFactory *iface )
+{
+ struct ramp_factory *impl = impl_from_IActivationFactory( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI activation_Release( IActivationFactory *iface )
+{
+ struct ramp_factory *impl = impl_from_IActivationFactory( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+ TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static HRESULT WINAPI activation_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids )
+{
+ FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI activation_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name )
+{
+ FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI activation_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level )
+{
+ FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI activation_ActivateInstance( IActivationFactory *iface, IInspectable **instance )
+{
+ struct ramp_effect *impl;
+ HRESULT hr;
+
+ TRACE( "iface %p, instance %p.\n", iface, instance );
+
+ if (!(impl = calloc( 1, sizeof(struct ramp_effect) ))) return E_OUTOFMEMORY;
+ impl->IRampForceEffect_iface.lpVtbl = &effect_vtbl;
+ impl->ref = 1;
+
+ if (FAILED(hr = force_feedback_effect_create( WineForceFeedbackEffectType_Ramp, (IInspectable *)&impl->IRampForceEffect_iface,
+ &impl->IWineForceFeedbackEffectImpl_inner )))
+ {
+ free( impl );
+ return hr;
+ }
+
+ *instance = (IInspectable *)&impl->IRampForceEffect_iface;
+ TRACE( "created RampForceEffect %p\n", *instance );
+ return S_OK;
+}
+
+static const struct IActivationFactoryVtbl activation_vtbl =
+{
+ activation_QueryInterface,
+ activation_AddRef,
+ activation_Release,
+ /* IInspectable methods */
+ activation_GetIids,
+ activation_GetRuntimeClassName,
+ activation_GetTrustLevel,
+ /* IActivationFactory methods */
+ activation_ActivateInstance,
+};
+
+static struct ramp_factory ramp_statics =
+{
+ {&activation_vtbl},
+ 1,
+};
+
+IInspectable *ramp_effect_factory = (IInspectable *)&ramp_statics.IActivationFactory_iface;
diff --git a/dlls/windows.gaming.input/vector.c b/dlls/windows.gaming.input/vector.c
index db1a9057682..8958b07c0f2 100644
--- wine/dlls/windows.gaming.input/vector.c
+++ wine/dlls/windows.gaming.input/vector.c
@@ -54,7 +54,7 @@ static HRESULT WINAPI iterator_QueryInterface( IIterator_IInspectable *iface, RE
return S_OK;
}
- WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
*out = NULL;
return E_NOINTERFACE;
}
@@ -189,7 +189,7 @@ static HRESULT WINAPI vector_view_QueryInterface( IVectorView_IInspectable *ifac
return S_OK;
}
- WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
*out = NULL;
return E_NOINTERFACE;
}
@@ -384,7 +384,7 @@ static HRESULT WINAPI vector_QueryInterface( IVector_IInspectable *iface, REFIID
return S_OK;
}
- WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
*out = NULL;
return E_NOINTERFACE;
}
diff --git a/include/Makefile.in b/include/Makefile.in
index 19d0088e431..cade5bb49dd 100644
--- wine/include/Makefile.in
+++ wine/include/Makefile.in
@@ -788,8 +788,10 @@ SOURCES = \
windows.foundation.collections.idl \
windows.foundation.idl \
windows.foundation.metadata.idl \
+ windows.foundation.numerics.idl \
windows.gaming.input.custom.idl \
windows.gaming.input.forcefeedback.idl \
+ windows.gaming.ui.idl \
windows.gaming.input.idl \
windows.globalization.idl \
windows.h \
diff --git a/include/windows.foundation.numerics.idl b/include/windows.foundation.numerics.idl
new file mode 100644
index 00000000000..eca99ca29bc
--- /dev/null
+++ wine/include/windows.foundation.numerics.idl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2022 Rémi Bernon for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef __WIDL__
+#pragma winrt ns_prefix
+#endif
+
+import "inspectable.idl";
+import "asyncinfo.idl";
+import "eventtoken.idl";
+import "windowscontracts.idl";
+import "windows.foundation.idl";
+
+namespace Windows.Foundation.Numerics {
+ typedef struct Vector3 Vector3;
+
+ [contract(Windows.Foundation.UniversalApiContract, 1.0)]
+ struct Vector3
+ {
+ FLOAT X;
+ FLOAT Y;
+ FLOAT Z;
+ };
+}
diff --git a/include/windows.gaming.input.forcefeedback.idl b/include/windows.gaming.input.forcefeedback.idl
index 432b60a5592..82fb083b34b 100644
--- wine/include/windows.gaming.input.forcefeedback.idl
+++ wine/include/windows.gaming.input.forcefeedback.idl
@@ -20,23 +20,41 @@
#pragma winrt ns_prefix
#endif
+#ifndef DO_NO_IMPORTS
import "inspectable.idl";
import "asyncinfo.idl";
import "eventtoken.idl";
import "windowscontracts.idl";
import "windows.foundation.idl";
+import "windows.foundation.numerics.idl";
+#endif
namespace Windows.Gaming.Input.ForceFeedback {
typedef enum ForceFeedbackEffectAxes ForceFeedbackEffectAxes;
typedef enum ForceFeedbackEffectState ForceFeedbackEffectState;
typedef enum ForceFeedbackLoadEffectResult ForceFeedbackLoadEffectResult;
+ typedef enum PeriodicForceEffectKind PeriodicForceEffectKind;
+ typedef enum ConditionForceEffectKind ConditionForceEffectKind;
interface IForceFeedbackEffect;
+ interface IPeriodicForceEffect;
+ interface IPeriodicForceEffectFactory;
+ interface IConditionForceEffect;
+ interface IConditionForceEffectFactory;
+ interface IConstantForceEffect;
+ interface IRampForceEffect;
runtimeclass ForceFeedbackMotor;
+ runtimeclass PeriodicForceEffect;
+ runtimeclass ConditionForceEffect;
+ runtimeclass ConstantForceEffect;
+ runtimeclass RampForceEffect;
declare {
interface Windows.Foundation.AsyncOperationCompletedHandler<Windows.Gaming.Input.ForceFeedback.ForceFeedbackLoadEffectResult>;
interface Windows.Foundation.IAsyncOperation<Windows.Gaming.Input.ForceFeedback.ForceFeedbackLoadEffectResult>;
+ interface Windows.Foundation.Collections.IIterator<Windows.Gaming.Input.ForceFeedback.ForceFeedbackMotor *>;
+ interface Windows.Foundation.Collections.IIterable<Windows.Gaming.Input.ForceFeedback.ForceFeedbackMotor *>;
interface Windows.Foundation.Collections.IVectorView<Windows.Gaming.Input.ForceFeedback.ForceFeedbackMotor *>;
+ interface Windows.Foundation.Collections.IVector<Windows.Gaming.Input.ForceFeedback.ForceFeedbackMotor *>;
}
[
@@ -68,6 +86,25 @@ namespace Windows.Gaming.Input.ForceFeedback {
EffectNotSupported = 2
};
+ [contract(Windows.Foundation.UniversalApiContract, 3.0)]
+ enum PeriodicForceEffectKind
+ {
+ SquareWave = 0,
+ SineWave = 1,
+ TriangleWave = 2,
+ SawtoothWaveUp = 3,
+ SawtoothWaveDown = 4,
+ };
+
+ [contract(Windows.Foundation.UniversalApiContract, 3.0)]
+ enum ConditionForceEffectKind
+ {
+ Spring = 0,
+ Damper = 1,
+ Inertia = 2,
+ Friction = 3,
+ };
+
[
contract(Windows.Foundation.UniversalApiContract, 3.0),
uuid(a17fba0c-2ae4-48c2-8063-eabd0777cb89)
@@ -105,6 +142,91 @@ namespace Windows.Gaming.Input.ForceFeedback {
[out, retval] Windows.Foundation.IAsyncOperation<boolean> **async_op);
}
+ [
+ contract(Windows.Foundation.UniversalApiContract, 3.0),
+ exclusiveto(Windows.Gaming.Input.ForceFeedback.PeriodicForceEffect),
+ uuid(5c5138d7-fc75-4d52-9a0a-efe4cab5fe64)
+ ]
+ interface IPeriodicForceEffect : IInspectable
+ requires Windows.Gaming.Input.ForceFeedback.IForceFeedbackEffect
+ {
+ [propget] HRESULT Kind([out, retval] Windows.Gaming.Input.ForceFeedback.PeriodicForceEffectKind *value);
+ HRESULT SetParameters([in] Windows.Foundation.Numerics.Vector3 vector, [in] FLOAT frequency, [in] FLOAT phase,
+ [in] FLOAT bias, [in] Windows.Foundation.TimeSpan duration);
+ HRESULT SetParametersWithEnvelope([in] Windows.Foundation.Numerics.Vector3 vector, [in] FLOAT frequency, [in] FLOAT phase,
+ [in] FLOAT bias, [in] FLOAT attack_gain, [in] FLOAT sustain_gain, [in] FLOAT release_gain,
+ [in] Windows.Foundation.TimeSpan start_delay, [in] Windows.Foundation.TimeSpan attack_duration,
+ [in] Windows.Foundation.TimeSpan sustain_duration, [in] Windows.Foundation.TimeSpan release_duration,
+ [in] UINT32 repeat_count);
+ }
+
+ [
+ contract(Windows.Foundation.UniversalApiContract, 3.0),
+ exclusiveto(Windows.Gaming.Input.ForceFeedback.PeriodicForceEffect),
+ uuid(6f62eb1a-9851-477b-b318-35ecaa15070f)
+ ]
+ interface IPeriodicForceEffectFactory : IInspectable
+ {
+ HRESULT CreateInstance([in] Windows.Gaming.Input.ForceFeedback.PeriodicForceEffectKind kind,
+ [out, retval] Windows.Gaming.Input.ForceFeedback.PeriodicForceEffect **value);
+ }
+
+ [
+ contract(Windows.Foundation.UniversalApiContract, 3.0),
+ exclusiveto(Windows.Gaming.Input.ForceFeedback.ConditionForceEffect),
+ uuid(32d1ea68-3695-4e69-85c0-cd1944189140)
+ ]
+ interface IConditionForceEffect : IInspectable
+ requires Windows.Gaming.Input.ForceFeedback.IForceFeedbackEffect
+ {
+ [propget] HRESULT Kind([out, retval] Windows.Gaming.Input.ForceFeedback.ConditionForceEffectKind *value);
+ HRESULT SetParameters([in] Windows.Foundation.Numerics.Vector3 direction, [in] FLOAT positive_coeff,
+ [in] FLOAT negative_coeff, [in] FLOAT max_positive_magnitude, [in] FLOAT max_negative_magnitude,
+ [in] FLOAT deadzone, [in] FLOAT bias);
+ }
+
+ [
+ contract(Windows.Foundation.UniversalApiContract, 3.0),
+ exclusiveto(Windows.Gaming.Input.ForceFeedback.ConditionForceEffect),
+ uuid(91a99264-1810-4eb6-a773-bfd3b8cddbab)
+ ]
+ interface IConditionForceEffectFactory : IInspectable
+ {
+ HRESULT CreateInstance([in] Windows.Gaming.Input.ForceFeedback.ConditionForceEffectKind kind,
+ [out, retval] Windows.Gaming.Input.ForceFeedback.ConditionForceEffect **value);
+ }
+
+ [
+ contract(Windows.Foundation.UniversalApiContract, 3.0),
+ exclusiveto(Windows.Gaming.Input.ForceFeedback.ConstantForceEffect),
+ uuid(9bfa0140-f3c7-415c-b068-0f068734bce0)
+ ]
+ interface IConstantForceEffect : IInspectable
+ requires Windows.Gaming.Input.ForceFeedback.IForceFeedbackEffect
+ {
+ HRESULT SetParameters([in] Windows.Foundation.Numerics.Vector3 vector, [in] Windows.Foundation.TimeSpan duration);
+ HRESULT SetParametersWithEnvelope([in] Windows.Foundation.Numerics.Vector3 vector, [in] FLOAT attack_gain,
+ [in] FLOAT sustain_gain, [in] FLOAT release_gain, [in] Windows.Foundation.TimeSpan start_delay,
+ [in] Windows.Foundation.TimeSpan attack_duration, [in] Windows.Foundation.TimeSpan sustain_duration,
+ [in] Windows.Foundation.TimeSpan release_duration, [in] UINT32 repeat_count);
+ }
+
+ [
+ contract(Windows.Foundation.UniversalApiContract, 3.0),
+ exclusiveto(Windows.Gaming.Input.ForceFeedback.RampForceEffect),
+ uuid(f1f81259-1ca6-4080-b56d-b43f3354d052)
+ ]
+ interface IRampForceEffect : IInspectable
+ requires Windows.Gaming.Input.ForceFeedback.IForceFeedbackEffect
+ {
+ HRESULT SetParameters([in] Windows.Foundation.Numerics.Vector3 start_vector, [in] Windows.Foundation.Numerics.Vector3 end_vector,
+ [in] Windows.Foundation.TimeSpan duration);
+ HRESULT SetParametersWithEnvelope([in] Windows.Foundation.Numerics.Vector3 start_vector, [in] Windows.Foundation.Numerics.Vector3 end_vector,
+ [in] FLOAT attack_gain, [in] FLOAT sustain_gain, [in] FLOAT release_gain, [in] Windows.Foundation.TimeSpan start_delay,
+ [in] Windows.Foundation.TimeSpan attack_duration, [in] Windows.Foundation.TimeSpan sustain_duration,
+ [in] Windows.Foundation.TimeSpan release_duration, [in] UINT32 repeat_count);
+ }
+
[
contract(Windows.Foundation.UniversalApiContract, 3.0),
marshaling_behavior(agile),
@@ -114,4 +236,52 @@ namespace Windows.Gaming.Input.ForceFeedback {
{
[default] interface Windows.Gaming.Input.ForceFeedback.IForceFeedbackMotor;
}
+
+ [
+ activatable(Windows.Gaming.Input.ForceFeedback.IPeriodicForceEffectFactory, Windows.Foundation.UniversalApiContract, 3.0),
+ contract(Windows.Foundation.UniversalApiContract, 3.0),
+ marshaling_behavior(agile),
+ threading(both)
+ ]
+ runtimeclass PeriodicForceEffect
+ {
+ [default] interface Windows.Gaming.Input.ForceFeedback.IForceFeedbackEffect;
+ interface Windows.Gaming.Input.ForceFeedback.IPeriodicForceEffect;
+ }
+
+ [
+ activatable(Windows.Gaming.Input.ForceFeedback.IConditionForceEffectFactory, Windows.Foundation.UniversalApiContract, 3.0),
+ contract(Windows.Foundation.UniversalApiContract, 3.0),
+ marshaling_behavior(agile),
+ threading(both)
+ ]
+ runtimeclass ConditionForceEffect
+ {
+ [default] interface Windows.Gaming.Input.ForceFeedback.IForceFeedbackEffect;
+ interface Windows.Gaming.Input.ForceFeedback.IConditionForceEffect;
+ }
+
+ [
+ activatable(Windows.Foundation.UniversalApiContract, 3.0),
+ contract(Windows.Foundation.UniversalApiContract, 3.0),
+ marshaling_behavior(agile),
+ threading(both)
+ ]
+ runtimeclass ConstantForceEffect
+ {
+ [default] interface Windows.Gaming.Input.ForceFeedback.IForceFeedbackEffect;
+ interface Windows.Gaming.Input.ForceFeedback.IConstantForceEffect;
+ }
+
+ [
+ activatable(Windows.Foundation.UniversalApiContract, 3.0),
+ contract(Windows.Foundation.UniversalApiContract, 3.0),
+ marshaling_behavior(agile),
+ threading(both)
+ ]
+ runtimeclass RampForceEffect
+ {
+ [default] interface Windows.Gaming.Input.ForceFeedback.IForceFeedbackEffect;
+ interface Windows.Gaming.Input.ForceFeedback.IRampForceEffect;
+ }
}
diff --git a/include/windows.gaming.input.idl b/include/windows.gaming.input.idl
index fdae3aa70b1..5fc5265247d 100644
--- wine/include/windows.gaming.input.idl
+++ wine/include/windows.gaming.input.idl
@@ -446,6 +446,19 @@ namespace Windows.Gaming.Input {
HRESULT GetCurrentReading([out, retval] Windows.Gaming.Input.GamepadReading *value);
}
+ [
+ contract(Windows.Foundation.UniversalApiContract, 3.0),
+ exclusiveto(Windows.Gaming.Input.Gamepad),
+ uuid(3c1689bd-5915-4245-b0c0-c89fae0308ff)
+ ]
+ interface IGamepad2 : IInspectable
+ requires Windows.Gaming.Input.IGamepad,
+ Windows.Gaming.Input.IGameController
+ {
+ HRESULT GetButtonLabel([in] Windows.Gaming.Input.GamepadButtons button,
+ [out, retval] Windows.Gaming.Input.GameControllerButtonLabel *value);
+ }
+
[
contract(Windows.Foundation.UniversalApiContract, 3.0),
exclusiveto(Windows.Gaming.Input.RacingWheel),
diff --git a/include/windows.gaming.ui.idl b/include/windows.gaming.ui.idl
new file mode 100644
index 00000000000..730f5dd90f7
--- /dev/null
+++ wine/include/windows.gaming.ui.idl
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2022 Paul Gofman for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef __WIDL__
+#pragma winrt ns_prefix
+#endif
+
+#ifndef DO_NO_IMPORTS
+import "inspectable.idl";
+import "eventtoken.idl";
+import "windowscontracts.idl";
+import "windows.foundation.idl";
+#endif
+
+namespace Windows.Gaming.UI {
+ runtimeclass GameBar;
+
+ declare {
+ interface Windows.Foundation.EventHandler<IInspectable *>;
+ }
+
+ [
+ contract(Windows.Foundation.UniversalApiContract, 2.0),
+ exclusiveto(Windows.Gaming.UI.GameBar),
+ uuid(1db9a292-cc78-4173-be45-b61e67283ea7)
+ ]
+ interface IGameBarStatics : IInspectable
+ {
+ [eventadd] HRESULT VisibilityChanged([in] Windows.Foundation.EventHandler<IInspectable *> *handler, [out, retval] EventRegistrationToken *token);
+ [eventremove] HRESULT VisibilityChanged([in] EventRegistrationToken token);
+ [eventadd] HRESULT IsInputRedirectedChanged([in] Windows.Foundation.EventHandler<IInspectable *> *handler, [out, retval] EventRegistrationToken *token);
+ [eventremove] HRESULT IsInputRedirectedChanged([in] EventRegistrationToken token);
+ [propget] HRESULT Visible([out] [retval] boolean* value);
+ [propget] HRESULT IsInputRedirected([out] [retval] boolean* value);
+ }
+
+ [
+ contract(Windows.Foundation.UniversalApiContract, 2.0),
+ marshaling_behavior(agile),
+ static(Windows.Gaming.UI.IGameBarStatics, Windows.Foundation.UniversalApiContract, 2.0),
+ threading(both)
+ ]
+ runtimeclass GameBar
+ {
+ }
+}
--
2.39.2 (Apple Git-144)
diff --git a/dlls/advapi32/advapi.c b/dlls/advapi32/advapi.c
index 6497ea22f4e..f7d6e973252 100644
--- wine/dlls/advapi32/advapi.c
+++ wine/dlls/advapi32/advapi.c
@@ -32,6 +32,7 @@
#include "winerror.h"
#include "wincred.h"
#include "wct.h"
+#include "perflib.h"
#include "wine/debug.h"
@@ -334,3 +335,50 @@ BOOL WINAPI GetThreadWaitChain(HWCT handle, DWORD_PTR ctx, DWORD flags, DWORD th
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
+
+ULONG WINAPI PerfCloseQueryHandle( HANDLE query )
+{
+ FIXME( "query %p stub.\n", query );
+
+ return ERROR_SUCCESS;
+}
+
+ULONG WINAPI PerfOpenQueryHandle( const WCHAR *machine, HANDLE *query )
+{
+ FIXME( "machine %s, query %p.\n", debugstr_w(machine), query );
+
+ if (!query) return ERROR_INVALID_PARAMETER;
+ *query = (HANDLE)0xdeadbeef;
+
+ return ERROR_SUCCESS;
+}
+
+ULONG WINAPI PerfAddCounters( HANDLE query, PERF_COUNTER_IDENTIFIER *id, DWORD size )
+{
+ FIXME( "query %p, id %p, size %lu stub.\n", query, id, size );
+
+ if (!id || size < sizeof(*id) || id->Size < sizeof(*id)) return ERROR_INVALID_PARAMETER;
+
+ id->Status = ERROR_WMI_GUID_NOT_FOUND;
+ return ERROR_SUCCESS;
+}
+
+ULONG WINAPI PerfQueryCounterData( HANDLE query, PERF_DATA_HEADER *data, DWORD data_size, DWORD *size_needed )
+{
+ FIXME( "query %p, data %p, data_size %lu, size_needed %p stub.\n", query, data, data_size, size_needed );
+
+ if (!size_needed) return ERROR_INVALID_PARAMETER;
+
+ *size_needed = sizeof(PERF_DATA_HEADER);
+
+ if (!data || data_size < sizeof(PERF_DATA_HEADER)) return ERROR_NOT_ENOUGH_MEMORY;
+
+ data->dwTotalSize = sizeof(PERF_DATA_HEADER);
+ data->dwNumCounters = 0;
+ QueryPerformanceCounter( (LARGE_INTEGER *)&data->PerfTimeStamp );
+ QueryPerformanceFrequency( (LARGE_INTEGER *)&data->PerfFreq );
+ GetSystemTimeAsFileTime( (FILETIME *)&data->PerfTime100NSec );
+ FileTimeToSystemTime( (FILETIME *)&data->PerfTime100NSec, &data->SystemTime );
+
+ return ERROR_SUCCESS;
+}
diff --git a/dlls/advapi32/advapi32.spec b/dlls/advapi32/advapi32.spec
index 3b5f587d40e..1c3f59bb7ee 100644
--- wine/dlls/advapi32/advapi32.spec
+++ wine/dlls/advapi32/advapi32.spec
@@ -553,8 +553,8 @@
@ stdcall -ret64 -import OpenTraceW(ptr)
# @ stub OperationEnd
# @ stub OperationStart
-# @ stub PerfAddCounters
-# @ stub PerfCloseQueryHandle
+@ stdcall PerfAddCounters(long ptr long)
+@ stdcall PerfCloseQueryHandle(long)
@ stdcall -import PerfCreateInstance(long ptr wstr long)
# @ stub PerfDecrementULongCounterValue
# @ stub PerfDecrementULongLongCounterValue
@@ -564,8 +564,8 @@
# @ stub PerfEnumerateCounterSetInstances
# @ stub PerfIncrementULongCounterValue
# @ stub PerfIncrementULongLongCounterValue
-# @ stub PerfOpenQueryHandle
-# @ stub PerfQueryCounterData
+@ stdcall PerfOpenQueryHandle(wstr ptr)
+@ stdcall PerfQueryCounterData(long ptr long ptr)
# @ stub PerfQueryCounterInfo
# @ stub PerfQueryCounterSetRegistrationInfo
# @ stub PerfQueryInstance
diff --git a/dlls/advapi32/tests/perf.c b/dlls/advapi32/tests/perf.c
index fc07a09d327..34b6e952842 100644
--- wine/dlls/advapi32/tests/perf.c
+++ wine/dlls/advapi32/tests/perf.c
@@ -25,9 +25,31 @@
#include "winerror.h"
#include "perflib.h"
#include "winperf.h"
+#include "winternl.h"
#include "wine/test.h"
+#include "initguid.h"
+
+#define DEFINE_FUNCTION(name) static typeof(name) *p##name;
+DEFINE_FUNCTION(PerfCloseQueryHandle);
+DEFINE_FUNCTION(PerfOpenQueryHandle);
+DEFINE_FUNCTION(PerfAddCounters);
+DEFINE_FUNCTION(PerfQueryCounterData);
+#undef DEFINE_FUNCTION
+
+static void init_functions(void)
+{
+ HANDLE hadvapi = GetModuleHandleA("advapi32.dll");
+
+#define GET_FUNCTION(name) p##name = (void *)GetProcAddress(hadvapi, #name)
+ GET_FUNCTION(PerfCloseQueryHandle);
+ GET_FUNCTION(PerfOpenQueryHandle);
+ GET_FUNCTION(PerfAddCounters);
+ GET_FUNCTION(PerfQueryCounterData);
+#undef GET_FUNCTION
+}
+
static ULONG WINAPI test_provider_callback(ULONG code, void *buffer, ULONG size)
{
ok(0, "Provider callback called.\n");
@@ -188,7 +210,94 @@ void test_provider_init(void)
ok(!ret, "Got unexpected ret %lu.\n", ret);
}
+DEFINE_GUID(TestCounterGUID, 0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33);
+
+static ULONG64 trunc_nttime_ms(ULONG64 t)
+{
+ return (t / 10000) * 10000;
+}
+
+static void test_perf_counters(void)
+{
+ LARGE_INTEGER freq, qpc1, qpc2, nttime1, nttime2, systime;
+ char buffer[sizeof(PERF_COUNTER_IDENTIFIER) + 8];
+ PERF_COUNTER_IDENTIFIER *counter_id;
+ PERF_DATA_HEADER dh;
+ HANDLE query;
+ DWORD size;
+ ULONG ret;
+
+ if (!pPerfOpenQueryHandle)
+ {
+ win_skip("PerfOpenQueryHandle not found.\n");
+ return;
+ }
+
+ ret = pPerfOpenQueryHandle(NULL, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "got ret %lu.\n", ret);
+ ret = pPerfOpenQueryHandle(NULL, &query);
+ ok(!ret, "got ret %lu.\n", ret);
+
+ counter_id = (PERF_COUNTER_IDENTIFIER *)buffer;
+ memset(buffer, 0, sizeof(buffer));
+
+ counter_id->CounterSetGuid = TestCounterGUID;
+ counter_id->CounterId = PERF_WILDCARD_COUNTER;
+ counter_id->InstanceId = PERF_WILDCARD_COUNTER;
+
+ ret = pPerfAddCounters(query, counter_id, sizeof(*counter_id));
+ ok(ret == ERROR_INVALID_PARAMETER, "got ret %lu.\n", ret);
+
+ counter_id->Size = sizeof(*counter_id);
+ ret = pPerfAddCounters(query, counter_id, 8);
+ ok(ret == ERROR_INVALID_PARAMETER, "got ret %lu.\n", ret);
+ ret = pPerfAddCounters(query, counter_id, sizeof(*counter_id));
+ ok(!ret, "got ret %lu.\n", ret);
+ ok(counter_id->Status == ERROR_WMI_GUID_NOT_FOUND, "got Status %#lx.\n", counter_id->Status);
+
+ ret = pPerfQueryCounterData(query, NULL, 0, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "got ret %lu.\n", ret);
+
+ size = 0xdeadbeef;
+ ret = pPerfQueryCounterData(query, NULL, 0, &size);
+ ok(ret == ERROR_NOT_ENOUGH_MEMORY, "got ret %lu.\n", ret);
+ ok(size == sizeof(dh), "got size %lu.\n", size);
+
+ ret = pPerfQueryCounterData(query, &dh, sizeof(dh), NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "got ret %lu.\n", ret);
+
+ QueryPerformanceFrequency(&freq);
+ QueryPerformanceCounter(&qpc1);
+ NtQuerySystemTime(&nttime1);
+
+ size = 0xdeadbeef;
+ ret = pPerfQueryCounterData(query, &dh, sizeof(dh), &size);
+ QueryPerformanceCounter(&qpc2);
+ NtQuerySystemTime(&nttime2);
+ SystemTimeToFileTime(&dh.SystemTime, (FILETIME *)&systime);
+ ok(!ret, "got ret %lu.\n", ret);
+ ok(size == sizeof(dh), "got size %lu.\n", size);
+ ok(dh.dwTotalSize == sizeof(dh), "got dwTotalSize %lu.\n", dh.dwTotalSize);
+ ok(!dh.dwNumCounters, "got dwNumCounters %lu.\n", dh.dwNumCounters);
+ ok(dh.PerfFreq == freq.QuadPart, "got PerfFreq %I64u.\n", dh.PerfFreq);
+ ok(dh.PerfTimeStamp >= qpc1.QuadPart && dh.PerfTimeStamp <= qpc2.QuadPart,
+ "got PerfTimeStamp %I64u, qpc1 %I64u, qpc2 %I64u.\n",
+ dh.PerfTimeStamp, qpc1.QuadPart, qpc2.QuadPart);
+ ok(dh.PerfTime100NSec >= nttime1.QuadPart && dh.PerfTime100NSec <= nttime2.QuadPart,
+ "got PerfTime100NSec %I64u, nttime1 %I64u, nttime2 %I64u.\n",
+ dh.PerfTime100NSec, nttime1.QuadPart, nttime2.QuadPart);
+ ok(systime.QuadPart >= trunc_nttime_ms(nttime1.QuadPart) && systime.QuadPart <= trunc_nttime_ms(nttime2.QuadPart),
+ "got systime %I64u, nttime1 %I64u, nttime2 %I64u, %d.\n",
+ systime.QuadPart, nttime1.QuadPart, nttime2.QuadPart, dh.SystemTime.wMilliseconds);
+
+ ret = pPerfCloseQueryHandle(query);
+ ok(!ret, "got ret %lu.\n", ret);
+}
+
START_TEST(perf)
{
+ init_functions();
+
test_provider_init();
+ test_perf_counters();
}
diff --git a/include/perflib.h b/include/perflib.h
index eb65f0802a4..40704aeb6f7 100644
--- wine/include/perflib.h
+++ wine/include/perflib.h
@@ -83,6 +83,28 @@ typedef struct _PROVIDER_CONTEXT {
LPVOID pMemContext;
} PERF_PROVIDER_CONTEXT, * PPERF_PROVIDER_CONTEXT;
+typedef struct _PERF_COUNTER_IDENTIFIER {
+ GUID CounterSetGuid;
+ ULONG Status;
+ ULONG Size;
+ ULONG CounterId;
+ ULONG InstanceId;
+ ULONG Index;
+ ULONG Reserved;
+} PERF_COUNTER_IDENTIFIER, *PPERF_COUNTER_IDENTIFIER;
+
+#define PERF_WILDCARD_COUNTER 0xFFFFFFFF
+#define PERF_WILDCARD_INSTANCE L"*"
+
+typedef struct _PERF_DATA_HEADER {
+ ULONG dwTotalSize;
+ ULONG dwNumCounters;
+ LONGLONG PerfTimeStamp;
+ LONGLONG PerfTime100NSec;
+ LONGLONG PerfFreq;
+ SYSTEMTIME SystemTime;
+} PERF_DATA_HEADER, *PPERF_DATA_HEADER;
+
PERF_COUNTERSET_INSTANCE WINAPI *PerfCreateInstance(HANDLE, const GUID *, const WCHAR *, ULONG);
ULONG WINAPI PerfDeleteInstance(HANDLE, PERF_COUNTERSET_INSTANCE *);
ULONG WINAPI PerfSetCounterRefValue(HANDLE, PERF_COUNTERSET_INSTANCE *, ULONG, void *);
@@ -91,6 +113,11 @@ ULONG WINAPI PerfStartProvider(GUID *, PERFLIBREQUEST, HANDLE *);
ULONG WINAPI PerfStartProviderEx(GUID *, PERF_PROVIDER_CONTEXT *, HANDLE *);
ULONG WINAPI PerfStopProvider(HANDLE);
+ULONG WINAPI PerfAddCounters(HANDLE, PERF_COUNTER_IDENTIFIER *, DWORD);
+ULONG WINAPI PerfCloseQueryHandle(HANDLE);
+ULONG WINAPI PerfOpenQueryHandle(const WCHAR *, HANDLE *);
+ULONG WINAPI PerfQueryCounterData(HANDLE, PERF_DATA_HEADER *, DWORD, DWORD *);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
--
2.39.2 (Apple Git-144)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 2ae9ccdc93f..51a14338d93 100644
--- wine/dlls/kernel32/kernel32.spec
+++ wine/dlls/kernel32/kernel32.spec
@@ -1470,6 +1470,7 @@
@ stdcall -import SetThreadGroupAffinity(long ptr ptr)
@ stdcall -import SetThreadIdealProcessor(long long)
@ stdcall -import SetThreadIdealProcessorEx(long ptr ptr)
+@ stdcall -import SetThreadInformation(long long ptr long)
@ stdcall -import SetThreadLocale(long)
@ stdcall -import SetThreadPreferredUILanguages(long ptr ptr)
@ stdcall -import SetThreadPriority(long long)
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index 00012198eb6..3fb2192b1ff 100644
--- wine/dlls/kernelbase/kernelbase.spec
+++ wine/dlls/kernelbase/kernelbase.spec
@@ -1519,7 +1519,7 @@
@ stdcall SetThreadGroupAffinity(long ptr ptr)
@ stdcall SetThreadIdealProcessor(long long)
@ stdcall SetThreadIdealProcessorEx(long ptr ptr)
-# @ stub SetThreadInformation
+@ stdcall SetThreadInformation(long long ptr long)
@ stdcall SetThreadLocale(long)
@ stdcall SetThreadPreferredUILanguages(long ptr ptr)
@ stdcall SetThreadPriority(long long)
diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c
index 1c878474acb..3f61ae46776 100644
--- wine/dlls/kernelbase/thread.c
+++ wine/dlls/kernelbase/thread.c
@@ -606,6 +606,25 @@ LANGID WINAPI DECLSPEC_HOTPATCH SetThreadUILanguage( LANGID langid )
}
+/**********************************************************************
+ * SetThreadInformation (kernelbase.@)
+ */
+BOOL WINAPI DECLSPEC_HOTPATCH SetThreadInformation( HANDLE thread, THREAD_INFORMATION_CLASS info_class,
+ VOID *info, DWORD size )
+{
+ switch (info_class)
+ {
+ case ThreadMemoryPriority:
+ return set_ntstatus( NtSetInformationThread( thread, ThreadPagePriority, info, size ));
+ case ThreadPowerThrottling:
+ return set_ntstatus( NtSetInformationThread( thread, ThreadPowerThrottlingState, info, size ));
+ default:
+ FIXME("Unsupported class %u.\n", info_class);
+ return FALSE;
+ }
+}
+
+
/**********************************************************************
* SuspendThread (kernelbase.@)
*/
diff --git a/include/processthreadsapi.h b/include/processthreadsapi.h
index 8cdaff4796a..d266b7a727b 100644
--- wine/include/processthreadsapi.h
+++ wine/include/processthreadsapi.h
@@ -23,8 +23,23 @@
extern "C" {
#endif
+typedef enum _THREAD_INFORMATION_CLASS
+{
+ ThreadMemoryPriority,
+ ThreadAbsoluteCpuPriority,
+ ThreadDynamicCodePolicy,
+ ThreadPowerThrottling,
+ ThreadInformationClassMax
+} THREAD_INFORMATION_CLASS;
+
+typedef struct _MEMORY_PRIORITY_INFORMATION
+{
+ ULONG MemoryPriority;
+} MEMORY_PRIORITY_INFORMATION, *PMEMORY_PRIORITY_INFORMATION;
+
WINBASEAPI HRESULT WINAPI GetThreadDescription(HANDLE,PWSTR *);
WINBASEAPI HRESULT WINAPI SetThreadDescription(HANDLE,PCWSTR);
+WINBASEAPI BOOL WINAPI SetThreadInformation(HANDLE,THREAD_INFORMATION_CLASS,LPVOID,DWORD);
#ifdef __cplusplus
}
--
2.39.2 (Apple Git-144)
diff --git a/configure b/configure
index cdf99fc287d..bfa6e1885a1 100755
--- wine/configure
+++ wine/configure
@@ -1424,6 +1424,7 @@ enable_wimgapi
enable_win32u
enable_windows_devices_enumeration
enable_windows_gaming_input
+enable_windows_gaming_ui_gamebar
enable_windows_globalization
enable_windows_media_devices
enable_windows_media_speech
@@ -22531,6 +22532,8 @@ wine_fn_config_makefile dlls/windebug.dll16 enable_win16
wine_fn_config_makefile dlls/windows.devices.enumeration enable_windows_devices_enumeration
wine_fn_config_makefile dlls/windows.gaming.input enable_windows_gaming_input
wine_fn_config_makefile dlls/windows.gaming.input/tests enable_tests
+wine_fn_config_makefile dlls/windows.gaming.ui.gamebar enable_windows_gaming_ui_gamebar
+wine_fn_config_makefile dlls/windows.gaming.ui.gamebar/tests enable_tests
wine_fn_config_makefile dlls/windows.globalization enable_windows_globalization
wine_fn_config_makefile dlls/windows.globalization/tests enable_tests
wine_fn_config_makefile dlls/windows.media.devices enable_windows_media_devices
diff --git a/configure.ac b/configure.ac
index c05d5b6f539..8fad7462dd9 100644
--- wine/configure.ac
+++ wine/configure.ac
@@ -3175,6 +3175,8 @@ WINE_CONFIG_MAKEFILE(dlls/windebug.dll16,enable_win16)
WINE_CONFIG_MAKEFILE(dlls/windows.devices.enumeration)
WINE_CONFIG_MAKEFILE(dlls/windows.gaming.input)
WINE_CONFIG_MAKEFILE(dlls/windows.gaming.input/tests)
+WINE_CONFIG_MAKEFILE(dlls/windows.gaming.ui.gamebar)
+WINE_CONFIG_MAKEFILE(dlls/windows.gaming.ui.gamebar/tests)
WINE_CONFIG_MAKEFILE(dlls/windows.globalization)
WINE_CONFIG_MAKEFILE(dlls/windows.globalization/tests)
WINE_CONFIG_MAKEFILE(dlls/windows.media.devices)
diff --git a/dlls/windows.gaming.ui.gamebar/Makefile.in b/dlls/windows.gaming.ui.gamebar/Makefile.in
new file mode 100644
index 00000000000..a0eefc4b951
--- /dev/null
+++ wine/dlls/windows.gaming.ui.gamebar/Makefile.in
@@ -0,0 +1,8 @@
+MODULE = windows.gaming.ui.gamebar.dll
+IMPORTS = combase uuid
+
+C_SRCS = \
+ main.c
+
+IDL_SRCS = \
+ classes.idl
diff --git a/dlls/windows.gaming.ui.gamebar/classes.idl b/dlls/windows.gaming.ui.gamebar/classes.idl
new file mode 100644
index 00000000000..ef10fcb6283
--- /dev/null
+++ wine/dlls/windows.gaming.ui.gamebar/classes.idl
@@ -0,0 +1,33 @@
+/*
+ * Runtime Classes for windows.gaming.ui.gamebar.dll
+ *
+ * Copyright 2022 Paul Gofman for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#pragma makedep register
+
+#ifdef __WIDL__
+#pragma winrt ns_prefix
+#endif
+
+import "inspectable.idl";
+import "eventtoken.idl";
+import "windowscontracts.idl";
+import "windows.foundation.idl";
+
+#define DO_NO_IMPORTS
+#include "windows.gaming.ui.idl"
diff --git a/dlls/windows.gaming.ui.gamebar/main.c b/dlls/windows.gaming.ui.gamebar/main.c
new file mode 100644
index 00000000000..ec6b442cfc0
--- /dev/null
+++ wine/dlls/windows.gaming.ui.gamebar/main.c
@@ -0,0 +1,282 @@
+/* WinRT Windows.Gaming.UI.GameBar implementation
+ *
+ * Copyright 2022 Paul Gofman for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#define COBJMACROS
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winuser.h"
+#include "winstring.h"
+
+#include "initguid.h"
+
+#define WIDL_using_Windows_Foundation
+#define WIDL_using_Windows_Gaming_UI
+#include "activation.h"
+#include "windows.gaming.ui.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(gamebar);
+
+static EventRegistrationToken dummy_token = {.value = 0xdeadbeef};
+
+struct gamebar_statics
+{
+ IActivationFactory IActivationFactory_iface;
+ IGameBarStatics IGameBarStatics_iface;
+ LONG ref;
+};
+
+static inline struct gamebar_statics *impl_from_IActivationFactory( IActivationFactory *iface )
+{
+ return CONTAINING_RECORD( iface, struct gamebar_statics, IActivationFactory_iface );
+}
+
+static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out )
+{
+ struct gamebar_statics *impl = impl_from_IActivationFactory( iface );
+
+ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out );
+
+ if (IsEqualGUID( iid, &IID_IUnknown ) ||
+ IsEqualGUID( iid, &IID_IInspectable ) ||
+ IsEqualGUID( iid, &IID_IAgileObject ) ||
+ IsEqualGUID( iid, &IID_IActivationFactory ))
+ {
+ IInspectable_AddRef( (*out = &impl->IActivationFactory_iface) );
+ return S_OK;
+ }
+
+ if (IsEqualGUID( iid, &IID_IGameBarStatics ))
+ {
+ IInspectable_AddRef( (*out = &impl->IGameBarStatics_iface) );
+ return S_OK;
+ }
+
+ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI factory_AddRef( IActivationFactory *iface )
+{
+ struct gamebar_statics *impl = impl_from_IActivationFactory( iface );
+ ULONG ref = InterlockedIncrement( &impl->ref );
+ TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static ULONG WINAPI factory_Release( IActivationFactory *iface )
+{
+ struct gamebar_statics *impl = impl_from_IActivationFactory( iface );
+ ULONG ref = InterlockedDecrement( &impl->ref );
+ TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+ return ref;
+}
+
+static HRESULT WINAPI factory_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids )
+{
+ FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name )
+{
+ FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level )
+{
+ FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance )
+{
+ FIXME( "iface %p, instance %p stub!\n", iface, instance );
+ return E_NOTIMPL;
+}
+
+static const struct IActivationFactoryVtbl factory_vtbl =
+{
+ factory_QueryInterface,
+ factory_AddRef,
+ factory_Release,
+ /* IInspectable methods */
+ factory_GetIids,
+ factory_GetRuntimeClassName,
+ factory_GetTrustLevel,
+ /* IActivationFactory methods */
+ factory_ActivateInstance,
+};
+
+#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \
+ static inline impl_type *impl_from( iface_type *iface ) \
+ { \
+ return CONTAINING_RECORD( iface, impl_type, iface_mem ); \
+ } \
+ static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \
+ { \
+ impl_type *impl = impl_from( iface ); \
+ return IInspectable_QueryInterface( (IInspectable *)(expr), iid, out ); \
+ } \
+ static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \
+ { \
+ impl_type *impl = impl_from( iface ); \
+ return IInspectable_AddRef( (IInspectable *)(expr) ); \
+ } \
+ static ULONG WINAPI pfx##_Release( iface_type *iface ) \
+ { \
+ impl_type *impl = impl_from( iface ); \
+ return IInspectable_Release( (IInspectable *)(expr) ); \
+ } \
+ static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \
+ { \
+ impl_type *impl = impl_from( iface ); \
+ return IInspectable_GetIids( (IInspectable *)(expr), iid_count, iids ); \
+ } \
+ static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \
+ { \
+ impl_type *impl = impl_from( iface ); \
+ return IInspectable_GetRuntimeClassName( (IInspectable *)(expr), class_name ); \
+ } \
+ static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \
+ { \
+ impl_type *impl = impl_from( iface ); \
+ return IInspectable_GetTrustLevel( (IInspectable *)(expr), trust_level ); \
+ }
+#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface ) \
+ DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface )
+
+DEFINE_IINSPECTABLE( statics, IGameBarStatics, struct gamebar_statics, IActivationFactory_iface )
+
+static HRESULT WINAPI statics_add_VisibilityChanged( IGameBarStatics *iface,
+ IEventHandler_IInspectable *handler,
+ EventRegistrationToken *token )
+{
+ FIXME( "iface %p, handler %p, token %p stub.\n", iface, handler, token );
+ *token = dummy_token;
+ return S_OK;
+}
+
+static HRESULT WINAPI statics_remove_VisibilityChanged( IGameBarStatics *iface, EventRegistrationToken token )
+{
+ FIXME( "iface %p, token %#I64x stub.\n", iface, token.value );
+ return S_OK;
+}
+
+static HRESULT WINAPI statics_add_IsInputRedirectedChanged( IGameBarStatics *iface,
+ IEventHandler_IInspectable *handler,
+ EventRegistrationToken *token )
+{
+ FIXME( "iface %p, handler %p, token %p stub.\n", iface, handler, token );
+ *token = dummy_token;
+ return S_OK;
+}
+
+static HRESULT WINAPI statics_remove_IsInputRedirectedChanged( IGameBarStatics *iface, EventRegistrationToken token )
+{
+ FIXME( "iface %p, token %#I64x stub.\n", iface, token.value );
+ return S_OK;
+}
+
+static HRESULT WINAPI statics_get_Visible( IGameBarStatics *iface, BOOLEAN *value)
+{
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (!value) return E_INVALIDARG;
+ *value = FALSE;
+ return S_OK;
+}
+
+static HRESULT WINAPI statics_get_IsInputRedirected( IGameBarStatics *iface, BOOLEAN *value)
+{
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (!value) return E_INVALIDARG;
+ *value = FALSE;
+ return S_OK;
+}
+
+static const struct IGameBarStaticsVtbl statics_vtbl =
+{
+ statics_QueryInterface,
+ statics_AddRef,
+ statics_Release,
+ /* IInspectable methods */
+ statics_GetIids,
+ statics_GetRuntimeClassName,
+ statics_GetTrustLevel,
+ /* IGameBarStatics methods */
+ statics_add_VisibilityChanged,
+ statics_remove_VisibilityChanged,
+ statics_add_IsInputRedirectedChanged,
+ statics_remove_IsInputRedirectedChanged,
+ statics_get_Visible,
+ statics_get_IsInputRedirected,
+};
+
+static struct gamebar_statics gamebar_statics =
+{
+ {&factory_vtbl},
+ {&statics_vtbl},
+ 1,
+};
+
+static IActivationFactory *gamebar_factory = &gamebar_statics.IActivationFactory_iface;
+
+HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
+{
+ FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out);
+
+ return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+HRESULT WINAPI DllGetActivationFactory( HSTRING class_str, IActivationFactory **factory )
+{
+ const WCHAR *buffer = WindowsGetStringRawBuffer( class_str, NULL );
+
+ TRACE( "class %s, factory %p.\n", debugstr_w(buffer), factory );
+
+ *factory = NULL;
+
+ if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_UI_GameBar ))
+ IActivationFactory_QueryInterface( gamebar_factory, &IID_IActivationFactory, (void **)factory );
+
+ if (*factory) return S_OK;
+ return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved )
+{
+ TRACE( "instance %p, reason %lu, reserved %p.\n", instance, reason, reserved );
+
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls( instance );
+ break;
+ }
+ return TRUE;
+}
diff --git a/dlls/windows.gaming.ui.gamebar/tests/Makefile.in b/dlls/windows.gaming.ui.gamebar/tests/Makefile.in
new file mode 100644
index 00000000000..67d70eee241
--- /dev/null
+++ wine/dlls/windows.gaming.ui.gamebar/tests/Makefile.in
@@ -0,0 +1,5 @@
+TESTDLL = windows.gaming.ui.gamebar.dll
+IMPORTS = combase
+
+C_SRCS = \
+ gamebar.c
diff --git a/dlls/windows.gaming.ui.gamebar/tests/gamebar.c b/dlls/windows.gaming.ui.gamebar/tests/gamebar.c
new file mode 100644
index 00000000000..14fcb05284f
--- /dev/null
+++ wine/dlls/windows.gaming.ui.gamebar/tests/gamebar.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2022 Paul Gofman for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#define COBJMACROS
+#include "initguid.h"
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winstring.h"
+
+#include "roapi.h"
+
+#define WIDL_using_Windows_Foundation
+#define WIDL_using_Windows_Gaming_UI
+#include "windows.foundation.h"
+#include "windows.gaming.ui.h"
+
+#include "wine/test.h"
+
+static void test_GameBarStatics(void)
+{
+ static const WCHAR *gamebar_statics_name = L"Windows.Gaming.UI.GameBar";
+
+ IActivationFactory *factory = NULL;
+ IInspectable *inspectable = NULL, *tmp_inspectable = NULL;
+ IAgileObject *agile_object = NULL, *tmp_agile_object = NULL;
+ IGameBarStatics *gamebar_statics = NULL;
+ HSTRING str;
+ HRESULT hr;
+
+ hr = WindowsCreateString(gamebar_statics_name, wcslen(gamebar_statics_name), &str);
+ ok(hr == S_OK, "WindowsCreateString failed, hr %#lx\n", hr);
+
+ hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory);
+ ok(hr == S_OK, "RoGetActivationFactory failed, hr %#lx\n", hr);
+ WindowsDeleteString(str);
+
+ /* interface tests */
+ hr = IActivationFactory_QueryInterface(factory, &IID_IInspectable, (void **)&inspectable);
+ ok(hr == S_OK, "IActivationFactory_QueryInterface IID_IInspectable failed, hr %#lx\n", hr);
+
+ hr = IActivationFactory_QueryInterface(factory, &IID_IAgileObject, (void **)&agile_object);
+ ok(hr == S_OK, "IActivationFactory_QueryInterface IID_IAgileObject failed, hr %#lx\n", hr);
+
+ hr = IActivationFactory_QueryInterface(factory, &IID_IGameBarStatics, (void **)&gamebar_statics);
+ ok(hr == S_OK, "IActivationFactory_QueryInterface IID_IMediaDeviceStatics failed, hr %#lx\n", hr);
+
+ hr = IGameBarStatics_QueryInterface(gamebar_statics, &IID_IInspectable, (void **)&tmp_inspectable);
+ ok(hr == S_OK, "IMediaDeviceStatics_QueryInterface IID_IInspectable failed, hr %#lx\n", hr);
+ ok(tmp_inspectable == inspectable, "IMediaDeviceStatics_QueryInterface IID_IInspectable returned %p, expected %p\n", tmp_inspectable, inspectable);
+ IInspectable_Release(tmp_inspectable);
+
+ hr = IGameBarStatics_QueryInterface(gamebar_statics, &IID_IAgileObject, (void **)&tmp_agile_object);
+ ok(hr == S_OK, "IMediaDeviceStatics_QueryInterface IID_IAgileObject failed, hr %#lx\n", hr);
+ ok(tmp_agile_object == agile_object, "IMediaDeviceStatics_QueryInterface IID_IAgileObject returned %p, expected %p\n", tmp_agile_object, agile_object);
+ IAgileObject_Release(tmp_agile_object);
+
+
+ IAgileObject_Release(agile_object);
+ IInspectable_Release(inspectable);
+ IActivationFactory_Release(factory);
+ IGameBarStatics_Release(gamebar_statics);
+}
+
+START_TEST(gamebar)
+{
+ HRESULT hr;
+
+ hr = RoInitialize(RO_INIT_MULTITHREADED);
+ ok(hr == S_OK, "RoInitialize failed, hr %#lx\n", hr);
+
+ test_GameBarStatics();
+
+ RoUninitialize();
+}
diff --git a/dlls/windows.gaming.ui.gamebar/windows.gaming.ui.gamebar.spec b/dlls/windows.gaming.ui.gamebar/windows.gaming.ui.gamebar.spec
new file mode 100644
index 00000000000..20a8bfa98ea
--- /dev/null
+++ wine/dlls/windows.gaming.ui.gamebar/windows.gaming.ui.gamebar.spec
@@ -0,0 +1,3 @@
+@ stdcall -private DllCanUnloadNow()
+@ stdcall -private DllGetActivationFactory(ptr ptr)
+@ stdcall -private DllGetClassObject(ptr ptr ptr)
--
2.39.2 (Apple Git-144)
diff --git a/dlls/mfmediaengine/Makefile.in b/dlls/mfmediaengine/Makefile.in
index a0e944c0633..bd273aafdab 100644
--- wine/dlls/mfmediaengine/Makefile.in
+++ wine/dlls/mfmediaengine/Makefile.in
@@ -1,4 +1,6 @@
+EXTRADEFS = -DWINE_NO_LONG_TYPES
MODULE = mfmediaengine.dll
+IMPORTLIB = mfmediaengine
IMPORTS = oleaut32 ole32 mfplat mf mfuuid dxguid uuid
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c
index a191448b69f..98504c5e269 100644
--- wine/dlls/mfmediaengine/main.c
+++ wine/dlls/mfmediaengine/main.c
@@ -29,8 +29,6 @@
#include "mferror.h"
#include "dxgi.h"
#include "d3d11.h"
-#include "mmdeviceapi.h"
-#include "audiosessiontypes.h"
#include "wine/debug.h"
@@ -115,8 +113,7 @@ struct rect
struct media_engine
{
- IMFMediaEngineEx IMFMediaEngineEx_iface;
- IMFGetService IMFGetService_iface;
+ IMFMediaEngine IMFMediaEngine_iface;
IMFAsyncCallback session_events;
IMFAsyncCallback load_handler;
IMFSampleGrabberSinkCallback grabber_callback;
@@ -141,11 +138,6 @@ struct media_engine
IMFSourceResolver *resolver;
BSTR current_source;
struct
- {
- IMFMediaSource *source;
- IMFPresentationDescriptor *pd;
- } presentation;
- struct
{
LONGLONG pts;
SIZE size;
@@ -214,7 +206,7 @@ static HRESULT media_engine_lock_d3d_device(struct media_engine *engine, ID3D11D
{
if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(engine->device_manager, &engine->device_handle)))
{
- WARN("Failed to open device handle, hr %#lx.\n", hr);
+ WARN("Failed to open device handle, hr %#x.\n", hr);
return hr;
}
}
@@ -230,7 +222,7 @@ static HRESULT media_engine_lock_d3d_device(struct media_engine *engine, ID3D11D
if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(engine->device_manager, &engine->device_handle)))
{
- WARN("Failed to open a device handle, hr %#lx.\n", hr);
+ WARN("Failed to open a device handle, hr %#x.\n", hr);
return hr;
}
hr = IMFDXGIDeviceManager_LockDevice(engine->device_manager, engine->device_handle, &IID_ID3D11Device,
@@ -340,7 +332,7 @@ static HRESULT media_engine_create_d3d11_video_frame_resources(struct media_engi
if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, &resource_data, &engine->video_frame.d3d11.vb)))
{
- WARN("Failed to create a vertex buffer, hr %#lx.\n", hr);
+ WARN("Failed to create a vertex buffer, hr %#x.\n", hr);
goto failed;
}
@@ -349,7 +341,7 @@ static HRESULT media_engine_create_d3d11_video_frame_resources(struct media_engi
if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, NULL, &engine->video_frame.d3d11.ps_cb)))
{
- WARN("Failed to create a buffer, hr %#lx.\n", hr);
+ WARN("Failed to create a buffer, hr %#x.\n", hr);
goto failed;
}
@@ -368,14 +360,14 @@ static HRESULT media_engine_create_d3d11_video_frame_resources(struct media_engi
if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &engine->video_frame.d3d11.source)))
{
- WARN("Failed to create source texture, hr %#lx.\n", hr);
+ WARN("Failed to create source texture, hr %#x.\n", hr);
goto failed;
}
if (FAILED(hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)engine->video_frame.d3d11.source,
NULL, &engine->video_frame.d3d11.srv)))
{
- WARN("Failed to create SRV, hr %#lx.\n", hr);
+ WARN("Failed to create SRV, hr %#x.\n", hr);
goto failed;
}
@@ -388,7 +380,7 @@ static HRESULT media_engine_create_d3d11_video_frame_resources(struct media_engi
if (FAILED(hr = ID3D11Device_CreateSamplerState(device, &sampler_desc, &engine->video_frame.d3d11.sampler)))
{
- WARN("Failed to create a sampler state, hr %#lx.\n", hr);
+ WARN("Failed to create a sampler state, hr %#x.\n", hr);
goto failed;
}
@@ -396,20 +388,20 @@ static HRESULT media_engine_create_d3d11_video_frame_resources(struct media_engi
if (FAILED(hr = ID3D11Device_CreateInputLayout(device, layout_desc, ARRAY_SIZE(layout_desc), vs_code, sizeof(vs_code),
&engine->video_frame.d3d11.input_layout)))
{
- WARN("Failed to create input layout, hr %#lx.\n", hr);
+ WARN("Failed to create input layout, hr %#x.\n", hr);
goto failed;
}
/* Shaders */
if (FAILED(hr = ID3D11Device_CreateVertexShader(device, vs_code, sizeof(vs_code), NULL, &engine->video_frame.d3d11.vs)))
{
- WARN("Failed to create the vertex shader, hr %#lx.\n", hr);
+ WARN("Failed to create the vertex shader, hr %#x.\n", hr);
goto failed;
}
if (FAILED(hr = ID3D11Device_CreatePixelShader(device, ps_code, sizeof(ps_code), NULL, &engine->video_frame.d3d11.ps)))
{
- WARN("Failed to create the pixel shader, hr %#lx.\n", hr);
+ WARN("Failed to create the pixel shader, hr %#x.\n", hr);
goto failed;
}
@@ -474,7 +466,7 @@ static ULONG WINAPI media_error_AddRef(IMFMediaError *iface)
struct media_error *me = impl_from_IMFMediaError(iface);
ULONG refcount = InterlockedIncrement(&me->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -484,7 +476,7 @@ static ULONG WINAPI media_error_Release(IMFMediaError *iface)
struct media_error *me = impl_from_IMFMediaError(iface);
ULONG refcount = InterlockedDecrement(&me->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
free(me);
@@ -524,7 +516,7 @@ static HRESULT WINAPI media_error_SetExtendedErrorCode(IMFMediaError *iface, HRE
{
struct media_error *me = impl_from_IMFMediaError(iface);
- TRACE("%p, %#lx.\n", iface, code);
+ TRACE("%p, %#x.\n", iface, code);
me->extended_code = code;
@@ -581,7 +573,7 @@ static ULONG WINAPI time_range_AddRef(IMFMediaTimeRange *iface)
struct time_range *range = impl_from_IMFMediaTimeRange(iface);
ULONG refcount = InterlockedIncrement(&range->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -591,7 +583,7 @@ static ULONG WINAPI time_range_Release(IMFMediaTimeRange *iface)
struct time_range *range = impl_from_IMFMediaTimeRange(iface);
ULONG refcount = InterlockedDecrement(&range->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
{
@@ -615,7 +607,7 @@ static HRESULT WINAPI time_range_GetStart(IMFMediaTimeRange *iface, DWORD idx, d
{
struct time_range *range = impl_from_IMFMediaTimeRange(iface);
- TRACE("%p, %lu, %p.\n", iface, idx, start);
+ TRACE("%p, %u, %p.\n", iface, idx, start);
if (idx >= range->count)
return E_INVALIDARG;
@@ -629,7 +621,7 @@ static HRESULT WINAPI time_range_GetEnd(IMFMediaTimeRange *iface, DWORD idx, dou
{
struct time_range *range = impl_from_IMFMediaTimeRange(iface);
- TRACE("%p, %lu, %p.\n", iface, idx, end);
+ TRACE("%p, %u, %p.\n", iface, idx, end);
if (idx >= range->count)
return E_INVALIDARG;
@@ -658,35 +650,13 @@ static BOOL WINAPI time_range_ContainsTime(IMFMediaTimeRange *iface, double time
static HRESULT WINAPI time_range_AddRange(IMFMediaTimeRange *iface, double start, double end)
{
struct time_range *range = impl_from_IMFMediaTimeRange(iface);
- struct range *c;
- size_t i;
TRACE("%p, %.8e, %.8e.\n", iface, start, end);
- for (i = 0; i < range->count; ++i)
+ if (range->count)
{
- c = &range->ranges[i];
-
- /* New range is fully contained within existing one. */
- if (c->start <= start && c->end >= end)
- return S_OK;
-
- /* New range fully contains existing one. */
- if (c->start >= start && c->end <= end)
- {
- c->start = start;
- c->end = end;
- return S_OK;
- }
-
- /* Merge if ranges intersect. */
- if ((start >= c->start && start <= c->end) ||
- (end >= c->start && end <= c->end))
- {
- c->start = min(c->start, start);
- c->end = max(c->end, end);
- return S_OK;
- }
+ FIXME("Range merging is not implemented.\n");
+ return E_NOTIMPL;
}
if (!mf_array_reserve((void **)&range->ranges, &range->capacity, range->count + 1, sizeof(*range->ranges)))
@@ -747,14 +717,9 @@ static void media_engine_set_flag(struct media_engine *engine, unsigned int mask
engine->flags &= ~mask;
}
-static inline struct media_engine *impl_from_IMFMediaEngineEx(IMFMediaEngineEx *iface)
+static inline struct media_engine *impl_from_IMFMediaEngine(IMFMediaEngine *iface)
{
- return CONTAINING_RECORD(iface, struct media_engine, IMFMediaEngineEx_iface);
-}
-
-static inline struct media_engine *impl_from_IMFGetService(IMFGetService *iface)
-{
- return CONTAINING_RECORD(iface, struct media_engine, IMFGetService_iface);
+ return CONTAINING_RECORD(iface, struct media_engine, IMFMediaEngine_iface);
}
static struct media_engine *impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback *iface)
@@ -819,7 +784,7 @@ static void media_engine_get_frame_size(struct media_engine *engine, IMFTopology
IMFMediaTypeHandler_Release(handler);
if (FAILED(hr))
{
- WARN("Failed to get current media type %#lx.\n", hr);
+ WARN("Failed to get current media type %#x.\n", hr);
return;
}
@@ -855,13 +820,13 @@ static HRESULT WINAPI media_engine_callback_QueryInterface(IMFAsyncCallback *ifa
static ULONG WINAPI media_engine_session_events_AddRef(IMFAsyncCallback *iface)
{
struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
- return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
+ return IMFMediaEngine_AddRef(&engine->IMFMediaEngine_iface);
}
static ULONG WINAPI media_engine_session_events_Release(IMFAsyncCallback *iface)
{
struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
- return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
+ return IMFMediaEngine_Release(&engine->IMFMediaEngine_iface);
}
static HRESULT WINAPI media_engine_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
@@ -878,13 +843,13 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface
if (FAILED(hr = IMFMediaSession_EndGetEvent(engine->session, result, &event)))
{
- WARN("Failed to get session event, hr %#lx.\n", hr);
+ WARN("Failed to get session event, hr %#x.\n", hr);
goto failed;
}
if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
{
- WARN("Failed to get event type, hr %#lx.\n", hr);
+ WARN("Failed to get event type, hr %#x.\n", hr);
goto failed;
}
@@ -960,7 +925,7 @@ failed:
IMFMediaEvent_Release(event);
if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, iface, NULL)))
- WARN("Failed to subscribe to session events, hr %#lx.\n", hr);
+ WARN("Failed to subscribe to session events, hr %#x.\n", hr);
return S_OK;
}
@@ -977,13 +942,13 @@ static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl =
static ULONG WINAPI media_engine_load_handler_AddRef(IMFAsyncCallback *iface)
{
struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
- return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
+ return IMFMediaEngine_AddRef(&engine->IMFMediaEngine_iface);
}
static ULONG WINAPI media_engine_load_handler_Release(IMFAsyncCallback *iface)
{
struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
- return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
+ return IMFMediaEngine_Release(&engine->IMFMediaEngine_iface);
}
static HRESULT media_engine_create_source_node(IMFMediaSource *source, IMFPresentationDescriptor *pd, IMFStreamDescriptor *sd,
@@ -1076,35 +1041,22 @@ static HRESULT media_engine_create_video_renderer(struct media_engine *engine, I
return hr;
}
-static void media_engine_clear_presentation(struct media_engine *engine)
-{
- if (engine->presentation.source)
- {
- IMFMediaSource_Shutdown(engine->presentation.source);
- IMFMediaSource_Release(engine->presentation.source);
- }
- if (engine->presentation.pd)
- IMFPresentationDescriptor_Release(engine->presentation.pd);
- memset(&engine->presentation, 0, sizeof(engine->presentation));
-}
-
static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source)
{
IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL;
+ unsigned int stream_count = 0, i;
IMFPresentationDescriptor *pd;
- DWORD stream_count = 0, i;
IMFTopology *topology;
UINT64 duration;
HRESULT hr;
media_engine_release_video_frame_resources(engine);
- media_engine_clear_presentation(engine);
if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
return hr;
if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(pd, &stream_count)))
- WARN("Failed to get stream count, hr %#lx.\n", hr);
+ WARN("Failed to get stream count, hr %#x.\n", hr);
/* Enable first video stream and first audio stream. */
@@ -1142,8 +1094,6 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi
IMFMediaTypeHandler_Release(type_handler);
}
-
- IMFStreamDescriptor_Release(sd);
}
if (!sd_video && !sd_audio)
@@ -1152,11 +1102,6 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi
return E_UNEXPECTED;
}
- engine->presentation.source = source;
- IMFMediaSource_AddRef(engine->presentation.source);
- engine->presentation.pd = pd;
- IMFPresentationDescriptor_AddRef(engine->presentation.pd);
-
media_engine_set_flag(engine, FLAGS_ENGINE_HAS_VIDEO, !!sd_video);
media_engine_set_flag(engine, FLAGS_ENGINE_HAS_AUDIO, !!sd_audio);
@@ -1174,16 +1119,13 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi
IMFTopologyNode *sar_node = NULL, *audio_src = NULL;
IMFTopologyNode *grabber_node = NULL, *video_src = NULL;
- if (engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE)
- IMFTopology_SetUINT32(topology, &MF_LOW_LATENCY, TRUE);
-
if (sd_audio)
{
if (FAILED(hr = media_engine_create_source_node(source, pd, sd_audio, &audio_src)))
- WARN("Failed to create audio source node, hr %#lx.\n", hr);
+ WARN("Failed to create audio source node, hr %#x.\n", hr);
if (FAILED(hr = media_engine_create_audio_renderer(engine, &sar_node)))
- WARN("Failed to create audio renderer node, hr %#lx.\n", hr);
+ WARN("Failed to create audio renderer node, hr %#x.\n", hr);
if (sar_node && audio_src)
{
@@ -1201,10 +1143,10 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi
if (SUCCEEDED(hr) && sd_video)
{
if (FAILED(hr = media_engine_create_source_node(source, pd, sd_video, &video_src)))
- WARN("Failed to create video source node, hr %#lx.\n", hr);
+ WARN("Failed to create video source node, hr %#x.\n", hr);
if (FAILED(hr = media_engine_create_video_renderer(engine, &grabber_node)))
- WARN("Failed to create video grabber node, hr %#lx.\n", hr);
+ WARN("Failed to create video grabber node, hr %#x.\n", hr);
if (grabber_node && video_src)
{
@@ -1252,10 +1194,10 @@ static void media_engine_start_playback(struct media_engine *engine)
static HRESULT WINAPI media_engine_load_handler_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
{
struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
- IUnknown *object = NULL, *state;
unsigned int start_playback;
MF_OBJECT_TYPE obj_type;
IMFMediaSource *source;
+ IUnknown *object = NULL;
HRESULT hr;
EnterCriticalSection(&engine->cs);
@@ -1266,16 +1208,8 @@ static HRESULT WINAPI media_engine_load_handler_Invoke(IMFAsyncCallback *iface,
start_playback = engine->flags & FLAGS_ENGINE_PLAY_PENDING;
media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING | FLAGS_ENGINE_PLAY_PENDING, FALSE);
- if (SUCCEEDED(IMFAsyncResult_GetState(result, &state)))
- {
- hr = IMFSourceResolver_EndCreateObjectFromByteStream(engine->resolver, result, &obj_type, &object);
- IUnknown_Release(state);
- }
- else
- hr = IMFSourceResolver_EndCreateObjectFromURL(engine->resolver, result, &obj_type, &object);
-
- if (FAILED(hr))
- WARN("Failed to create source object, hr %#lx.\n", hr);
+ if (FAILED(hr = IMFSourceResolver_EndCreateObjectFromURL(engine->resolver, result, &obj_type, &object)))
+ WARN("Failed to create source object, hr %#x.\n", hr);
if (object)
{
@@ -1316,39 +1250,29 @@ static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl =
media_engine_load_handler_Invoke,
};
-static HRESULT WINAPI media_engine_QueryInterface(IMFMediaEngineEx *iface, REFIID riid, void **obj)
+static HRESULT WINAPI media_engine_QueryInterface(IMFMediaEngine *iface, REFIID riid, void **obj)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
-
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
- if (IsEqualIID(riid, &IID_IMFMediaEngineEx) ||
- IsEqualIID(riid, &IID_IMFMediaEngine) ||
+ if (IsEqualIID(riid, &IID_IMFMediaEngine) ||
IsEqualIID(riid, &IID_IUnknown))
{
*obj = iface;
- }
- else if (IsEqualIID(riid, &IID_IMFGetService))
- {
- *obj = &engine->IMFGetService_iface;
- }
- else
- {
- WARN("Unsupported interface %s.\n", debugstr_guid(riid));
- *obj = NULL;
- return E_NOINTERFACE;
+ IMFMediaEngine_AddRef(iface);
+ return S_OK;
}
- IUnknown_AddRef((IUnknown *)*obj);
- return S_OK;
+ WARN("Unsupported interface %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
}
-static ULONG WINAPI media_engine_AddRef(IMFMediaEngineEx *iface)
+static ULONG WINAPI media_engine_AddRef(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
ULONG refcount = InterlockedIncrement(&engine->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -1366,7 +1290,6 @@ static void free_media_engine(struct media_engine *engine)
if (engine->resolver)
IMFSourceResolver_Release(engine->resolver);
media_engine_release_video_frame_resources(engine);
- media_engine_clear_presentation(engine);
if (engine->device_manager)
{
IMFDXGIDeviceManager_CloseDeviceHandle(engine->device_manager, engine->device_handle);
@@ -1378,12 +1301,12 @@ static void free_media_engine(struct media_engine *engine)
free(engine);
}
-static ULONG WINAPI media_engine_Release(IMFMediaEngineEx *iface)
+static ULONG WINAPI media_engine_Release(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
ULONG refcount = InterlockedDecrement(&engine->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
free_media_engine(engine);
@@ -1391,9 +1314,9 @@ static ULONG WINAPI media_engine_Release(IMFMediaEngineEx *iface)
return refcount;
}
-static HRESULT WINAPI media_engine_GetError(IMFMediaEngineEx *iface, IMFMediaError **error)
+static HRESULT WINAPI media_engine_GetError(IMFMediaEngine *iface, IMFMediaError **error)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr = S_OK;
TRACE("%p, %p.\n", iface, error);
@@ -1416,9 +1339,9 @@ static HRESULT WINAPI media_engine_GetError(IMFMediaEngineEx *iface, IMFMediaErr
return hr;
}
-static HRESULT WINAPI media_engine_SetErrorCode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_ERR code)
+static HRESULT WINAPI media_engine_SetErrorCode(IMFMediaEngine *iface, MF_MEDIA_ENGINE_ERR code)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr = S_OK;
TRACE("%p, %u.\n", iface, code);
@@ -1436,76 +1359,66 @@ static HRESULT WINAPI media_engine_SetErrorCode(IMFMediaEngineEx *iface, MF_MEDI
return hr;
}
-static HRESULT WINAPI media_engine_SetSourceElements(IMFMediaEngineEx *iface, IMFMediaEngineSrcElements *elements)
+static HRESULT WINAPI media_engine_SetSourceElements(IMFMediaEngine *iface, IMFMediaEngineSrcElements *elements)
{
FIXME("(%p, %p): stub.\n", iface, elements);
return E_NOTIMPL;
}
-static HRESULT media_engine_set_source(struct media_engine *engine, IMFByteStream *bytestream, BSTR url)
+static HRESULT WINAPI media_engine_SetSource(IMFMediaEngine *iface, BSTR url)
{
- IPropertyStore *props = NULL;
- unsigned int flags;
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr = S_OK;
- SysFreeString(engine->current_source);
- engine->current_source = NULL;
- if (url)
- engine->current_source = SysAllocString(url);
-
- engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_NOTHING;
-
- IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
+ TRACE("%p, %s.\n", iface, debugstr_w(url));
- engine->network_state = MF_MEDIA_ENGINE_NETWORK_NO_SOURCE;
+ EnterCriticalSection(&engine->cs);
- if (url || bytestream)
+ if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
+ hr = MF_E_SHUTDOWN;
+ else
{
- flags = MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE;
- if (engine->flags & MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS)
- flags |= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS;
+ SysFreeString(engine->current_source);
+ engine->current_source = NULL;
+ if (url)
+ engine->current_source = SysAllocString(url);
- IMFAttributes_GetUnknown(engine->attributes, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE,
- &IID_IPropertyStore, (void **)&props);
- if (bytestream)
- hr = IMFSourceResolver_BeginCreateObjectFromByteStream(engine->resolver, bytestream, url, flags,
- props, NULL, &engine->load_handler, (IUnknown *)bytestream);
- else
- hr = IMFSourceResolver_BeginCreateObjectFromURL(engine->resolver, url, flags, props, NULL,
- &engine->load_handler, NULL);
- if (SUCCEEDED(hr))
- media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING, TRUE);
+ engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_NOTHING;
- if (props)
- IPropertyStore_Release(props);
- }
+ IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
- return hr;
-}
+ engine->network_state = MF_MEDIA_ENGINE_NETWORK_NO_SOURCE;
-static HRESULT WINAPI media_engine_SetSource(IMFMediaEngineEx *iface, BSTR url)
-{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr;
+ if (url)
+ {
+ IPropertyStore *props = NULL;
+ unsigned int flags;
- TRACE("%p, %s.\n", iface, debugstr_w(url));
+ flags = MF_RESOLUTION_MEDIASOURCE;
+ if (engine->flags & MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS)
+ flags |= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS;
- EnterCriticalSection(&engine->cs);
+ IMFAttributes_GetUnknown(engine->attributes, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE,
+ &IID_IPropertyStore, (void **)&props);
+ hr = IMFSourceResolver_BeginCreateObjectFromURL(engine->resolver, url, flags, props, NULL,
+ &engine->load_handler, NULL);
+ if (SUCCEEDED(hr))
+ media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING, TRUE);
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else
- hr = media_engine_set_source(engine, NULL, url);
+ if (props)
+ IPropertyStore_Release(props);
+ }
+ }
LeaveCriticalSection(&engine->cs);
return hr;
}
-static HRESULT WINAPI media_engine_GetCurrentSource(IMFMediaEngineEx *iface, BSTR *url)
+static HRESULT WINAPI media_engine_GetCurrentSource(IMFMediaEngine *iface, BSTR *url)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr = S_OK;
TRACE("%p, %p.\n", iface, url);
@@ -1513,32 +1426,28 @@ static HRESULT WINAPI media_engine_GetCurrentSource(IMFMediaEngineEx *iface, BST
*url = NULL;
EnterCriticalSection(&engine->cs);
-
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
if (engine->current_source)
{
if (!(*url = SysAllocString(engine->current_source)))
hr = E_OUTOFMEMORY;
}
-
LeaveCriticalSection(&engine->cs);
return hr;
}
-static USHORT WINAPI media_engine_GetNetworkState(IMFMediaEngineEx *iface)
+static USHORT WINAPI media_engine_GetNetworkState(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
TRACE("%p.\n", iface);
return engine->network_state;
}
-static MF_MEDIA_ENGINE_PRELOAD WINAPI media_engine_GetPreload(IMFMediaEngineEx *iface)
+static MF_MEDIA_ENGINE_PRELOAD WINAPI media_engine_GetPreload(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
MF_MEDIA_ENGINE_PRELOAD preload;
TRACE("%p.\n", iface);
@@ -1550,9 +1459,9 @@ static MF_MEDIA_ENGINE_PRELOAD WINAPI media_engine_GetPreload(IMFMediaEngineEx *
return preload;
}
-static HRESULT WINAPI media_engine_SetPreload(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_PRELOAD preload)
+static HRESULT WINAPI media_engine_SetPreload(IMFMediaEngine *iface, MF_MEDIA_ENGINE_PRELOAD preload)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
TRACE("%p, %d.\n", iface, preload);
@@ -1563,9 +1472,9 @@ static HRESULT WINAPI media_engine_SetPreload(IMFMediaEngineEx *iface, MF_MEDIA_
return S_OK;
}
-static HRESULT WINAPI media_engine_GetBuffered(IMFMediaEngineEx *iface, IMFMediaTimeRange **range)
+static HRESULT WINAPI media_engine_GetBuffered(IMFMediaEngine *iface, IMFMediaTimeRange **range)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr;
TRACE("%p, %p.\n", iface, range);
@@ -1574,54 +1483,30 @@ static HRESULT WINAPI media_engine_GetBuffered(IMFMediaEngineEx *iface, IMFMedia
return hr;
EnterCriticalSection(&engine->cs);
-
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else if (!isnan(engine->duration))
+ if (!isnan(engine->duration))
hr = IMFMediaTimeRange_AddRange(*range, 0.0, engine->duration);
-
LeaveCriticalSection(&engine->cs);
return hr;
}
-static HRESULT WINAPI media_engine_Load(IMFMediaEngineEx *iface)
+static HRESULT WINAPI media_engine_Load(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr = E_NOTIMPL;
-
FIXME("(%p): stub.\n", iface);
- EnterCriticalSection(&engine->cs);
-
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
-
- LeaveCriticalSection(&engine->cs);
-
- return hr;
+ return E_NOTIMPL;
}
-static HRESULT WINAPI media_engine_CanPlayType(IMFMediaEngineEx *iface, BSTR type, MF_MEDIA_ENGINE_CANPLAY *answer)
+static HRESULT WINAPI media_engine_CanPlayType(IMFMediaEngine *iface, BSTR type, MF_MEDIA_ENGINE_CANPLAY *answer)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr = E_NOTIMPL;
-
FIXME("(%p, %s, %p): stub.\n", iface, debugstr_w(type), answer);
- EnterCriticalSection(&engine->cs);
-
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
-
- LeaveCriticalSection(&engine->cs);
-
- return hr;
+ return E_NOTIMPL;
}
-static USHORT WINAPI media_engine_GetReadyState(IMFMediaEngineEx *iface)
+static USHORT WINAPI media_engine_GetReadyState(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
unsigned short state;
TRACE("%p.\n", iface);
@@ -1633,16 +1518,16 @@ static USHORT WINAPI media_engine_GetReadyState(IMFMediaEngineEx *iface)
return state;
}
-static BOOL WINAPI media_engine_IsSeeking(IMFMediaEngineEx *iface)
+static BOOL WINAPI media_engine_IsSeeking(IMFMediaEngine *iface)
{
FIXME("(%p): stub.\n", iface);
return FALSE;
}
-static double WINAPI media_engine_GetCurrentTime(IMFMediaEngineEx *iface)
+static double WINAPI media_engine_GetCurrentTime(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
double ret = 0.0;
MFTIME clocktime;
@@ -1662,33 +1547,23 @@ static double WINAPI media_engine_GetCurrentTime(IMFMediaEngineEx *iface)
return ret;
}
-static HRESULT WINAPI media_engine_SetCurrentTime(IMFMediaEngineEx *iface, double time)
+static HRESULT WINAPI media_engine_SetCurrentTime(IMFMediaEngine *iface, double time)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr = E_NOTIMPL;
-
FIXME("(%p, %f): stub.\n", iface, time);
- EnterCriticalSection(&engine->cs);
-
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
-
- LeaveCriticalSection(&engine->cs);
-
- return hr;
+ return E_NOTIMPL;
}
-static double WINAPI media_engine_GetStartTime(IMFMediaEngineEx *iface)
+static double WINAPI media_engine_GetStartTime(IMFMediaEngine *iface)
{
FIXME("(%p): stub.\n", iface);
return 0.0;
}
-static double WINAPI media_engine_GetDuration(IMFMediaEngineEx *iface)
+static double WINAPI media_engine_GetDuration(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
double value;
TRACE("%p.\n", iface);
@@ -1700,9 +1575,9 @@ static double WINAPI media_engine_GetDuration(IMFMediaEngineEx *iface)
return value;
}
-static BOOL WINAPI media_engine_IsPaused(IMFMediaEngineEx *iface)
+static BOOL WINAPI media_engine_IsPaused(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
BOOL value;
TRACE("%p.\n", iface);
@@ -1714,9 +1589,9 @@ static BOOL WINAPI media_engine_IsPaused(IMFMediaEngineEx *iface)
return value;
}
-static double WINAPI media_engine_GetDefaultPlaybackRate(IMFMediaEngineEx *iface)
+static double WINAPI media_engine_GetDefaultPlaybackRate(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
double rate;
TRACE("%p.\n", iface);
@@ -1728,9 +1603,9 @@ static double WINAPI media_engine_GetDefaultPlaybackRate(IMFMediaEngineEx *iface
return rate;
}
-static HRESULT WINAPI media_engine_SetDefaultPlaybackRate(IMFMediaEngineEx *iface, double rate)
+static HRESULT WINAPI media_engine_SetDefaultPlaybackRate(IMFMediaEngine *iface, double rate)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr = S_OK;
TRACE("%p, %f.\n", iface, rate);
@@ -1748,9 +1623,9 @@ static HRESULT WINAPI media_engine_SetDefaultPlaybackRate(IMFMediaEngineEx *ifac
return hr;
}
-static double WINAPI media_engine_GetPlaybackRate(IMFMediaEngineEx *iface)
+static double WINAPI media_engine_GetPlaybackRate(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
double rate;
TRACE("%p.\n", iface);
@@ -1762,9 +1637,9 @@ static double WINAPI media_engine_GetPlaybackRate(IMFMediaEngineEx *iface)
return rate;
}
-static HRESULT WINAPI media_engine_SetPlaybackRate(IMFMediaEngineEx *iface, double rate)
+static HRESULT WINAPI media_engine_SetPlaybackRate(IMFMediaEngine *iface, double rate)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr = S_OK;
TRACE("%p, %f.\n", iface, rate);
@@ -1782,43 +1657,23 @@ static HRESULT WINAPI media_engine_SetPlaybackRate(IMFMediaEngineEx *iface, doub
return hr;
}
-static HRESULT WINAPI media_engine_GetPlayed(IMFMediaEngineEx *iface, IMFMediaTimeRange **played)
+static HRESULT WINAPI media_engine_GetPlayed(IMFMediaEngine *iface, IMFMediaTimeRange **played)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr = E_NOTIMPL;
-
FIXME("(%p, %p): stub.\n", iface, played);
- EnterCriticalSection(&engine->cs);
-
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
-
- LeaveCriticalSection(&engine->cs);
-
- return hr;
+ return E_NOTIMPL;
}
-static HRESULT WINAPI media_engine_GetSeekable(IMFMediaEngineEx *iface, IMFMediaTimeRange **seekable)
+static HRESULT WINAPI media_engine_GetSeekable(IMFMediaEngine *iface, IMFMediaTimeRange **seekable)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr = E_NOTIMPL;
-
FIXME("(%p, %p): stub.\n", iface, seekable);
- EnterCriticalSection(&engine->cs);
-
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
-
- LeaveCriticalSection(&engine->cs);
-
- return hr;
+ return E_NOTIMPL;
}
-static BOOL WINAPI media_engine_IsEnded(IMFMediaEngineEx *iface)
+static BOOL WINAPI media_engine_IsEnded(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
BOOL value;
TRACE("%p.\n", iface);
@@ -1830,9 +1685,9 @@ static BOOL WINAPI media_engine_IsEnded(IMFMediaEngineEx *iface)
return value;
}
-static BOOL WINAPI media_engine_GetAutoPlay(IMFMediaEngineEx *iface)
+static BOOL WINAPI media_engine_GetAutoPlay(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
BOOL value;
TRACE("%p.\n", iface);
@@ -1844,9 +1699,9 @@ static BOOL WINAPI media_engine_GetAutoPlay(IMFMediaEngineEx *iface)
return value;
}
-static HRESULT WINAPI media_engine_SetAutoPlay(IMFMediaEngineEx *iface, BOOL autoplay)
+static HRESULT WINAPI media_engine_SetAutoPlay(IMFMediaEngine *iface, BOOL autoplay)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
FIXME("(%p, %d): stub.\n", iface, autoplay);
@@ -1857,9 +1712,9 @@ static HRESULT WINAPI media_engine_SetAutoPlay(IMFMediaEngineEx *iface, BOOL aut
return S_OK;
}
-static BOOL WINAPI media_engine_GetLoop(IMFMediaEngineEx *iface)
+static BOOL WINAPI media_engine_GetLoop(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
BOOL value;
TRACE("%p.\n", iface);
@@ -1871,9 +1726,9 @@ static BOOL WINAPI media_engine_GetLoop(IMFMediaEngineEx *iface)
return value;
}
-static HRESULT WINAPI media_engine_SetLoop(IMFMediaEngineEx *iface, BOOL loop)
+static HRESULT WINAPI media_engine_SetLoop(IMFMediaEngine *iface, BOOL loop)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
FIXME("(%p, %d): stub.\n", iface, loop);
@@ -1884,75 +1739,63 @@ static HRESULT WINAPI media_engine_SetLoop(IMFMediaEngineEx *iface, BOOL loop)
return S_OK;
}
-static HRESULT WINAPI media_engine_Play(IMFMediaEngineEx *iface)
+static HRESULT WINAPI media_engine_Play(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr = S_OK;
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
TRACE("%p.\n", iface);
EnterCriticalSection(&engine->cs);
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else
- {
- IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
-
- if (!(engine->flags & FLAGS_ENGINE_WAITING))
- {
- media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED | FLAGS_ENGINE_IS_ENDED, FALSE);
- IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAY, 0, 0);
+ IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
- if (!(engine->flags & FLAGS_ENGINE_SOURCE_PENDING))
- media_engine_start_playback(engine);
- else
- media_engine_set_flag(engine, FLAGS_ENGINE_PLAY_PENDING, TRUE);
+ if (!(engine->flags & FLAGS_ENGINE_WAITING))
+ {
+ media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED | FLAGS_ENGINE_IS_ENDED, FALSE);
+ IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAY, 0, 0);
- media_engine_set_flag(engine, FLAGS_ENGINE_WAITING, TRUE);
- }
+ if (!(engine->flags & FLAGS_ENGINE_SOURCE_PENDING))
+ media_engine_start_playback(engine);
+ else
+ media_engine_set_flag(engine, FLAGS_ENGINE_PLAY_PENDING, TRUE);
- IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_WAITING, 0, 0);
+ media_engine_set_flag(engine, FLAGS_ENGINE_WAITING, TRUE);
}
+ IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_WAITING, 0, 0);
+
LeaveCriticalSection(&engine->cs);
- return hr;
+ return S_OK;
}
-static HRESULT WINAPI media_engine_Pause(IMFMediaEngineEx *iface)
+static HRESULT WINAPI media_engine_Pause(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr = S_OK;
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
TRACE("%p.\n", iface);
EnterCriticalSection(&engine->cs);
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else
+ if (!(engine->flags & FLAGS_ENGINE_PAUSED))
{
- if (!(engine->flags & FLAGS_ENGINE_PAUSED))
- {
- media_engine_set_flag(engine, FLAGS_ENGINE_WAITING | FLAGS_ENGINE_IS_ENDED, FALSE);
- media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED, TRUE);
-
- IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, 0, 0);
- IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PAUSE, 0, 0);
- }
+ media_engine_set_flag(engine, FLAGS_ENGINE_WAITING | FLAGS_ENGINE_IS_ENDED, FALSE);
+ media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED, TRUE);
- IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
+ IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, 0, 0);
+ IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PAUSE, 0, 0);
}
+ IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
+
LeaveCriticalSection(&engine->cs);
- return hr;
+ return S_OK;
}
-static BOOL WINAPI media_engine_GetMuted(IMFMediaEngineEx *iface)
+static BOOL WINAPI media_engine_GetMuted(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
BOOL ret;
TRACE("%p.\n", iface);
@@ -1964,9 +1807,9 @@ static BOOL WINAPI media_engine_GetMuted(IMFMediaEngineEx *iface)
return ret;
}
-static HRESULT WINAPI media_engine_SetMuted(IMFMediaEngineEx *iface, BOOL muted)
+static HRESULT WINAPI media_engine_SetMuted(IMFMediaEngine *iface, BOOL muted)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr = S_OK;
TRACE("%p, %d.\n", iface, muted);
@@ -1984,9 +1827,9 @@ static HRESULT WINAPI media_engine_SetMuted(IMFMediaEngineEx *iface, BOOL muted)
return hr;
}
-static double WINAPI media_engine_GetVolume(IMFMediaEngineEx *iface)
+static double WINAPI media_engine_GetVolume(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
double volume;
TRACE("%p.\n", iface);
@@ -1998,9 +1841,9 @@ static double WINAPI media_engine_GetVolume(IMFMediaEngineEx *iface)
return volume;
}
-static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngineEx *iface, double volume)
+static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngine *iface, double volume)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr = S_OK;
TRACE("%p, %f.\n", iface, volume);
@@ -2018,9 +1861,9 @@ static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngineEx *iface, double vol
return hr;
}
-static BOOL WINAPI media_engine_HasVideo(IMFMediaEngineEx *iface)
+static BOOL WINAPI media_engine_HasVideo(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
BOOL value;
TRACE("%p.\n", iface);
@@ -2032,9 +1875,9 @@ static BOOL WINAPI media_engine_HasVideo(IMFMediaEngineEx *iface)
return value;
}
-static BOOL WINAPI media_engine_HasAudio(IMFMediaEngineEx *iface)
+static BOOL WINAPI media_engine_HasAudio(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
BOOL value;
TRACE("%p.\n", iface);
@@ -2046,9 +1889,9 @@ static BOOL WINAPI media_engine_HasAudio(IMFMediaEngineEx *iface)
return value;
}
-static HRESULT WINAPI media_engine_GetNativeVideoSize(IMFMediaEngineEx *iface, DWORD *cx, DWORD *cy)
+static HRESULT WINAPI media_engine_GetNativeVideoSize(IMFMediaEngine *iface, DWORD *cx, DWORD *cy)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr = S_OK;
TRACE("%p, %p, %p.\n", iface, cx, cy);
@@ -2073,9 +1916,9 @@ static HRESULT WINAPI media_engine_GetNativeVideoSize(IMFMediaEngineEx *iface, D
return hr;
}
-static HRESULT WINAPI media_engine_GetVideoAspectRatio(IMFMediaEngineEx *iface, DWORD *cx, DWORD *cy)
+static HRESULT WINAPI media_engine_GetVideoAspectRatio(IMFMediaEngine *iface, DWORD *cx, DWORD *cy)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr = S_OK;
TRACE("%p, %p, %p.\n", iface, cx, cy);
@@ -2100,9 +1943,9 @@ static HRESULT WINAPI media_engine_GetVideoAspectRatio(IMFMediaEngineEx *iface,
return hr;
}
-static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngineEx *iface)
+static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngine *iface)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr = S_OK;
FIXME("(%p): stub.\n", iface);
@@ -2113,7 +1956,6 @@ static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngineEx *iface)
else
{
media_engine_set_flag(engine, FLAGS_ENGINE_SHUT_DOWN, TRUE);
- media_engine_clear_presentation(engine);
IMFMediaSession_Shutdown(engine->session);
}
LeaveCriticalSection(&engine->cs);
@@ -2215,7 +2057,7 @@ static HRESULT media_engine_transfer_to_d3d11_texture(struct media_engine *engin
if (FAILED(hr = media_engine_create_d3d11_video_frame_resources(engine, device)))
{
- WARN("Failed to create d3d resources, hr %#lx.\n", hr);
+ WARN("Failed to create d3d resources, hr %#x.\n", hr);
goto done;
}
@@ -2234,7 +2076,7 @@ static HRESULT media_engine_transfer_to_d3d11_texture(struct media_engine *engin
if (FAILED(hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)texture, NULL, &rtv)))
{
- WARN("Failed to create an rtv, hr %#lx.\n", hr);
+ WARN("Failed to create an rtv, hr %#x.\n", hr);
goto done;
}
@@ -2343,10 +2185,10 @@ done:
return hr;
}
-static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, IUnknown *surface,
+static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngine *iface, IUnknown *surface,
const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
ID3D11Texture2D *texture;
HRESULT hr = E_NOINTERFACE;
@@ -2371,9 +2213,9 @@ static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, I
return hr;
}
-static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngineEx *iface, LONGLONG *pts)
+static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngine *iface, LONGLONG *pts)
{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
HRESULT hr;
TRACE("%p, %p.\n", iface, pts);
@@ -2395,390 +2237,7 @@ static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngineEx *iface, LO
return hr;
}
-static HRESULT WINAPI media_engine_SetSourceFromByteStream(IMFMediaEngineEx *iface, IMFByteStream *bytestream, BSTR url)
-{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr;
-
- TRACE("%p, %p, %s.\n", iface, bytestream, debugstr_w(url));
-
- EnterCriticalSection(&engine->cs);
-
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else if (!bytestream || !url)
- hr = E_POINTER;
- else
- hr = media_engine_set_source(engine, bytestream, url);
-
- LeaveCriticalSection(&engine->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI media_engine_GetStatistics(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_STATISTIC stat_id, PROPVARIANT *stat)
-{
- FIXME("%p, %x, %p stub.\n", iface, stat_id, stat);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_UpdateVideoStream(IMFMediaEngineEx *iface, const MFVideoNormalizedRect *src,
- const RECT *dst, const MFARGB *border_color)
-{
- FIXME("%p, %p, %p, %p stub.\n", iface, src, dst, border_color);
-
- return E_NOTIMPL;
-}
-
-static double WINAPI media_engine_GetBalance(IMFMediaEngineEx *iface)
-{
- FIXME("%p stub.\n", iface);
-
- return 0.0;
-}
-
-static HRESULT WINAPI media_engine_SetBalance(IMFMediaEngineEx *iface, double balance)
-{
- FIXME("%p, %f stub.\n", iface, balance);
-
- return E_NOTIMPL;
-}
-
-static BOOL WINAPI media_engine_IsPlaybackRateSupported(IMFMediaEngineEx *iface, double rate)
-{
- FIXME("%p, %f stub.\n", iface, rate);
-
- return FALSE;
-}
-
-static HRESULT WINAPI media_engine_FrameStep(IMFMediaEngineEx *iface, BOOL forward)
-{
- FIXME("%p, %d stub.\n", iface, forward);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_GetResourceCharacteristics(IMFMediaEngineEx *iface, DWORD *flags)
-{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr = E_FAIL;
-
- TRACE("%p, %p.\n", iface, flags);
-
- EnterCriticalSection(&engine->cs);
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else if (engine->presentation.source)
- hr = IMFMediaSource_GetCharacteristics(engine->presentation.source, flags);
- LeaveCriticalSection(&engine->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI media_engine_GetPresentationAttribute(IMFMediaEngineEx *iface, REFGUID attribute,
- PROPVARIANT *value)
-{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr = E_FAIL;
-
- TRACE("%p, %s, %p.\n", iface, debugstr_guid(attribute), value);
-
- EnterCriticalSection(&engine->cs);
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else if (engine->presentation.pd)
- hr = IMFPresentationDescriptor_GetItem(engine->presentation.pd, attribute, value);
- LeaveCriticalSection(&engine->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI media_engine_GetNumberOfStreams(IMFMediaEngineEx *iface, DWORD *stream_count)
-{
- FIXME("%p, %p stub.\n", iface, stream_count);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_GetStreamAttribute(IMFMediaEngineEx *iface, DWORD stream_index, REFGUID attribute,
- PROPVARIANT *value)
-{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- IMFStreamDescriptor *sd;
- HRESULT hr = E_FAIL;
- BOOL selected;
-
- TRACE("%p, %ld, %s, %p.\n", iface, stream_index, debugstr_guid(attribute), value);
-
- EnterCriticalSection(&engine->cs);
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else if (engine->presentation.pd)
- {
- if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(engine->presentation.pd,
- stream_index, &selected, &sd)))
- {
- hr = IMFStreamDescriptor_GetItem(sd, attribute, value);
- IMFStreamDescriptor_Release(sd);
- }
- }
- LeaveCriticalSection(&engine->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI media_engine_GetStreamSelection(IMFMediaEngineEx *iface, DWORD stream_index, BOOL *enabled)
-{
- FIXME("%p, %ld, %p stub.\n", iface, stream_index, enabled);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_SetStreamSelection(IMFMediaEngineEx *iface, DWORD stream_index, BOOL enabled)
-{
- FIXME("%p, %ld, %d stub.\n", iface, stream_index, enabled);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_ApplyStreamSelections(IMFMediaEngineEx *iface)
-{
- FIXME("%p stub.\n", iface);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_IsProtected(IMFMediaEngineEx *iface, BOOL *protected)
-{
- FIXME("%p, %p stub.\n", iface, protected);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional)
-{
- FIXME("%p, %p, %d stub.\n", iface, effect, is_optional);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional)
-{
- FIXME("%p, %p, %d stub.\n", iface, effect, is_optional);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_RemoveAllEffects(IMFMediaEngineEx *iface)
-{
- FIXME("%p stub.\n", iface);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_SetTimelineMarkerTimer(IMFMediaEngineEx *iface, double timeout)
-{
- FIXME("%p, %f stub.\n", iface, timeout);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_GetTimelineMarkerTimer(IMFMediaEngineEx *iface, double *timeout)
-{
- FIXME("%p, %p stub.\n", iface, timeout);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_CancelTimelineMarkerTimer(IMFMediaEngineEx *iface)
-{
- FIXME("%p stub.\n", iface);
-
- return E_NOTIMPL;
-}
-
-static BOOL WINAPI media_engine_IsStereo3D(IMFMediaEngineEx *iface)
-{
- FIXME("%p stub.\n", iface);
-
- return FALSE;
-}
-
-static HRESULT WINAPI media_engine_GetStereo3DFramePackingMode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_S3D_PACKING_MODE *mode)
-{
- FIXME("%p, %p stub.\n", iface, mode);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_SetStereo3DFramePackingMode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_S3D_PACKING_MODE mode)
-{
- FIXME("%p, %#x stub.\n", iface, mode);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_GetStereo3DRenderMode(IMFMediaEngineEx *iface, MF3DVideoOutputType *output_type)
-{
- FIXME("%p, %p stub.\n", iface, output_type);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_SetStereo3DRenderMode(IMFMediaEngineEx *iface, MF3DVideoOutputType output_type)
-{
- FIXME("%p, %#x stub.\n", iface, output_type);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_EnableWindowlessSwapchainMode(IMFMediaEngineEx *iface, BOOL enable)
-{
- FIXME("%p, %d stub.\n", iface, enable);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_GetVideoSwapchainHandle(IMFMediaEngineEx *iface, HANDLE *swapchain)
-{
- FIXME("%p, %p stub.\n", iface, swapchain);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_EnableHorizontalMirrorMode(IMFMediaEngineEx *iface, BOOL enable)
-{
- FIXME("%p, %d stub.\n", iface, enable);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_GetAudioStreamCategory(IMFMediaEngineEx *iface, UINT32 *category)
-{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr;
-
- TRACE("%p, %p.\n", iface, category);
-
- EnterCriticalSection(&engine->cs);
-
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else
- hr = IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, category);
-
- LeaveCriticalSection(&engine->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI media_engine_SetAudioStreamCategory(IMFMediaEngineEx *iface, UINT32 category)
-{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr;
-
- TRACE("%p, %u.\n", iface, category);
-
- EnterCriticalSection(&engine->cs);
-
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else
- hr = IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, category);
-
- LeaveCriticalSection(&engine->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI media_engine_GetAudioEndpointRole(IMFMediaEngineEx *iface, UINT32 *role)
-{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr;
-
- TRACE("%p, %p.\n", iface, role);
-
- EnterCriticalSection(&engine->cs);
-
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else
- hr = IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, role);
-
- LeaveCriticalSection(&engine->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI media_engine_SetAudioEndpointRole(IMFMediaEngineEx *iface, UINT32 role)
-{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr;
-
- TRACE("%p, %u.\n", iface, role);
-
- EnterCriticalSection(&engine->cs);
-
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else
- hr = IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, role);
-
- LeaveCriticalSection(&engine->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI media_engine_GetRealTimeMode(IMFMediaEngineEx *iface, BOOL *enabled)
-{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr = S_OK;
-
- TRACE("%p, %p.\n", iface, enabled);
-
- EnterCriticalSection(&engine->cs);
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else
- *enabled = !!(engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE);
- LeaveCriticalSection(&engine->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI media_engine_SetRealTimeMode(IMFMediaEngineEx *iface, BOOL enable)
-{
- struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
- HRESULT hr = S_OK;
-
- TRACE("%p, %d.\n", iface, enable);
-
- EnterCriticalSection(&engine->cs);
- if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else
- media_engine_set_flag(engine, MF_MEDIA_ENGINE_REAL_TIME_MODE, enable);
- LeaveCriticalSection(&engine->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI media_engine_SetCurrentTimeEx(IMFMediaEngineEx *iface, double seektime, MF_MEDIA_ENGINE_SEEK_MODE mode)
-{
- FIXME("%p, %f, %#x stub.\n", iface, seektime, mode);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_engine_EnableTimeUpdateTimer(IMFMediaEngineEx *iface, BOOL enable)
-{
- FIXME("%p, %d stub.\n", iface, enable);
-
- return E_NOTIMPL;
-}
-
-static const IMFMediaEngineExVtbl media_engine_vtbl =
+static const IMFMediaEngineVtbl media_engine_vtbl =
{
media_engine_QueryInterface,
media_engine_AddRef,
@@ -2825,77 +2284,6 @@ static const IMFMediaEngineExVtbl media_engine_vtbl =
media_engine_Shutdown,
media_engine_TransferVideoFrame,
media_engine_OnVideoStreamTick,
- media_engine_SetSourceFromByteStream,
- media_engine_GetStatistics,
- media_engine_UpdateVideoStream,
- media_engine_GetBalance,
- media_engine_SetBalance,
- media_engine_IsPlaybackRateSupported,
- media_engine_FrameStep,
- media_engine_GetResourceCharacteristics,
- media_engine_GetPresentationAttribute,
- media_engine_GetNumberOfStreams,
- media_engine_GetStreamAttribute,
- media_engine_GetStreamSelection,
- media_engine_SetStreamSelection,
- media_engine_ApplyStreamSelections,
- media_engine_IsProtected,
- media_engine_InsertVideoEffect,
- media_engine_InsertAudioEffect,
- media_engine_RemoveAllEffects,
- media_engine_SetTimelineMarkerTimer,
- media_engine_GetTimelineMarkerTimer,
- media_engine_CancelTimelineMarkerTimer,
- media_engine_IsStereo3D,
- media_engine_GetStereo3DFramePackingMode,
- media_engine_SetStereo3DFramePackingMode,
- media_engine_GetStereo3DRenderMode,
- media_engine_SetStereo3DRenderMode,
- media_engine_EnableWindowlessSwapchainMode,
- media_engine_GetVideoSwapchainHandle,
- media_engine_EnableHorizontalMirrorMode,
- media_engine_GetAudioStreamCategory,
- media_engine_SetAudioStreamCategory,
- media_engine_GetAudioEndpointRole,
- media_engine_SetAudioEndpointRole,
- media_engine_GetRealTimeMode,
- media_engine_SetRealTimeMode,
- media_engine_SetCurrentTimeEx,
- media_engine_EnableTimeUpdateTimer,
-};
-
-static HRESULT WINAPI media_engine_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
-{
- struct media_engine *engine = impl_from_IMFGetService(iface);
- return IMFMediaEngineEx_QueryInterface(&engine->IMFMediaEngineEx_iface, riid, obj);
-}
-
-static ULONG WINAPI media_engine_gs_AddRef(IMFGetService *iface)
-{
- struct media_engine *engine = impl_from_IMFGetService(iface);
- return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
-}
-
-static ULONG WINAPI media_engine_gs_Release(IMFGetService *iface)
-{
- struct media_engine *engine = impl_from_IMFGetService(iface);
- return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
-}
-
-static HRESULT WINAPI media_engine_gs_GetService(IMFGetService *iface, REFGUID service,
- REFIID riid, void **object)
-{
- FIXME("%p, %s, %s, %p stub.\n", iface, debugstr_guid(service), debugstr_guid(riid), object);
-
- return E_NOTIMPL;
-}
-
-static const IMFGetServiceVtbl media_engine_get_service_vtbl =
-{
- media_engine_gs_QueryInterface,
- media_engine_gs_AddRef,
- media_engine_gs_Release,
- media_engine_gs_GetService,
};
static HRESULT WINAPI media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback *iface,
@@ -2916,13 +2304,13 @@ static HRESULT WINAPI media_engine_grabber_callback_QueryInterface(IMFSampleGrab
static ULONG WINAPI media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback *iface)
{
struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
- return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
+ return IMFMediaEngine_AddRef(&engine->IMFMediaEngine_iface);
}
static ULONG WINAPI media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback *iface)
{
struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
- return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
+ return IMFMediaEngine_Release(&engine->IMFMediaEngine_iface);
}
static HRESULT WINAPI media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback *iface,
@@ -3051,8 +2439,7 @@ static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct
IMFClock *clock;
HRESULT hr;
- engine->IMFMediaEngineEx_iface.lpVtbl = &media_engine_vtbl;
- engine->IMFGetService_iface.lpVtbl = &media_engine_get_service_vtbl;
+ engine->IMFMediaEngine_iface.lpVtbl = &media_engine_vtbl;
engine->session_events.lpVtbl = &media_engine_session_events_vtbl;
engine->load_handler.lpVtbl = &media_engine_load_handler_vtbl;
engine->grabber_callback.lpVtbl = &media_engine_grabber_callback_vtbl;
@@ -3096,12 +2483,6 @@ static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct
if (FAILED(hr = IMFAttributes_CopyAllItems(attributes, engine->attributes)))
return hr;
- /* Set default audio configuration */
- if (FAILED(IMFAttributes_GetItem(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, NULL)))
- IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, AudioCategory_Other);
- if (FAILED(IMFAttributes_GetItem(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, NULL)))
- IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, eMultimedia);
-
IMFAttributes_GetUINT64(attributes, &MF_MEDIA_ENGINE_PLAYBACK_HWND, &playback_hwnd);
hr = IMFAttributes_GetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format);
if (playback_hwnd) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
@@ -3123,7 +2504,7 @@ static HRESULT WINAPI media_engine_factory_CreateInstance(IMFMediaEngineClassFac
struct media_engine *object;
HRESULT hr;
- TRACE("%p, %#lx, %p, %p.\n", iface, flags, attributes, engine);
+ TRACE("%p, %#x, %p, %p.\n", iface, flags, attributes, engine);
if (!attributes || !engine)
return E_POINTER;
@@ -3139,7 +2520,7 @@ static HRESULT WINAPI media_engine_factory_CreateInstance(IMFMediaEngineClassFac
return hr;
}
- *engine = (IMFMediaEngine *)&object->IMFMediaEngineEx_iface;
+ *engine = &object->IMFMediaEngine_iface;
return S_OK;
}
diff --git a/dlls/mfmediaengine/tests/Makefile.in b/dlls/mfmediaengine/tests/Makefile.in
index 421b75587a0..13bbef64df2 100644
--- wine/dlls/mfmediaengine/tests/Makefile.in
+++ wine/dlls/mfmediaengine/tests/Makefile.in
@@ -1,5 +1,6 @@
+EXTRADEFS = -DWINE_NO_LONG_TYPES
TESTDLL = mfmediaengine.dll
-IMPORTS = ole32 mfplat oleaut32 mfuuid uuid
+IMPORTS = ole32 mfplat mfmediaengine oleaut32 mfuuid uuid
C_SRCS = \
mfmediaengine.c
diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c
index 008ee58849c..096f6e3f2a5 100644
--- wine/dlls/mfmediaengine/tests/mfmediaengine.c
+++ wine/dlls/mfmediaengine/tests/mfmediaengine.c
@@ -29,9 +29,8 @@
#include "mferror.h"
#include "dxgi.h"
#include "initguid.h"
-#include "mmdeviceapi.h"
-#include "audiosessiontypes.h"
+#include "wine/heap.h"
#include "wine/test.h"
static HRESULT (WINAPI *pMFCreateDXGIDeviceManager)(UINT *token, IMFDXGIDeviceManager **manager);
@@ -44,22 +43,7 @@ static void _expect_ref(IUnknown *obj, ULONG ref, int line)
ULONG rc;
IUnknown_AddRef(obj);
rc = IUnknown_Release(obj);
- ok_(__FILE__,line)(rc == ref, "Unexpected refcount %ld, expected %ld.\n", rc, ref);
-}
-
-#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
-static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
-{
- IUnknown *iface = iface_ptr;
- HRESULT hr, expected_hr;
- IUnknown *unk;
-
- expected_hr = supported ? S_OK : E_NOINTERFACE;
-
- hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
- ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr);
- if (SUCCEEDED(hr))
- IUnknown_Release(unk);
+ ok_(__FILE__,line)(rc == ref, "Unexpected refcount %d, expected %d.\n", rc, ref);
}
static void init_functions(void)
@@ -105,12 +89,7 @@ static ULONG WINAPI media_engine_notify_AddRef(IMFMediaEngineNotify *iface)
static ULONG WINAPI media_engine_notify_Release(IMFMediaEngineNotify *iface)
{
struct media_engine_notify *notify = impl_from_IMFMediaEngineNotify(iface);
- ULONG refcount = InterlockedDecrement(&notify->refcount);
-
- if (!refcount)
- free(notify);
-
- return refcount;
+ return InterlockedDecrement(&notify->refcount);
}
static HRESULT WINAPI media_engine_notify_EventNotify(IMFMediaEngineNotify *iface, DWORD event, DWORD_PTR param1, DWORD param2)
@@ -126,18 +105,6 @@ static IMFMediaEngineNotifyVtbl media_engine_notify_vtbl =
media_engine_notify_EventNotify,
};
-static struct media_engine_notify *create_callback(void)
-{
- struct media_engine_notify *object;
-
- object = calloc(1, sizeof(*object));
-
- object->IMFMediaEngineNotify_iface.lpVtbl = &media_engine_notify_vtbl;
- object->refcount = 1;
-
- return object;
-}
-
static IMFMediaEngine *create_media_engine(IMFMediaEngineNotify *callback)
{
IMFDXGIDeviceManager *manager;
@@ -147,18 +114,18 @@ static IMFMediaEngine *create_media_engine(IMFMediaEngineNotify *callback)
HRESULT hr;
hr = pMFCreateDXGIDeviceManager(&token, &manager);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Failed to create dxgi device manager, hr %#x.\n", hr);
hr = MFCreateAttributes(&attributes, 3);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Failed to create attributes, hr %#x.\n", hr);
hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, (IUnknown *)callback);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
hr = IMFAttributes_SetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, DXGI_FORMAT_UNKNOWN);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
hr = IMFMediaEngineClassFactory_CreateInstance(factory, 0, attributes, &media_engine);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Failed to create media engine, hr %#x.\n", hr);
IMFAttributes_Release(attributes);
IMFDXGIDeviceManager_Release(manager);
@@ -166,24 +133,11 @@ static IMFMediaEngine *create_media_engine(IMFMediaEngineNotify *callback)
return media_engine;
}
-static IMFMediaEngineEx *create_media_engine_ex(IMFMediaEngineNotify *callback)
-{
- IMFMediaEngine *engine = create_media_engine(callback);
- IMFMediaEngineEx *engine_ex = NULL;
-
- if (engine)
- {
- IMFMediaEngine_QueryInterface(engine, &IID_IMFMediaEngineEx, (void **)&engine_ex);
- IMFMediaEngine_Release(engine);
- }
-
- return engine_ex;
-}
-
static void test_factory(void)
{
+ struct media_engine_notify notify_impl = {{&media_engine_notify_vtbl}, 1};
+ IMFMediaEngineNotify *notify = &notify_impl.IMFMediaEngineNotify_iface;
IMFMediaEngineClassFactory *factory, *factory2;
- struct media_engine_notify *notify;
IMFDXGIDeviceManager *manager;
IMFMediaEngine *media_engine;
IMFAttributes *attributes;
@@ -192,158 +146,118 @@ static void test_factory(void)
hr = CoCreateInstance(&CLSID_MFMediaEngineClassFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IMFMediaEngineClassFactory,
(void **)&factory);
- ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /* pre-win8 */, "Failed to create class factory, hr %#lx.\n", hr);
+ ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /* pre-win8 */, "Failed to create class factory, hr %#x.\n", hr);
if (FAILED(hr))
{
win_skip("Media Engine is not supported.\n");
return;
}
- notify = create_callback();
-
/* Aggregation is not supported. */
hr = CoCreateInstance(&CLSID_MFMediaEngineClassFactory, (IUnknown *)factory, CLSCTX_INPROC_SERVER,
&IID_IMFMediaEngineClassFactory, (void **)&factory2);
- ok(hr == CLASS_E_NOAGGREGATION, "Unexpected hr %#lx.\n", hr);
+ ok(hr == CLASS_E_NOAGGREGATION, "Unexpected hr %#x.\n", hr);
hr = pMFCreateDXGIDeviceManager(&token, &manager);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "MFCreateDXGIDeviceManager failed: %#x.\n", hr);
hr = MFCreateAttributes(&attributes, 3);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "MFCreateAttributes failed: %#x.\n", hr);
- hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE, attributes, &media_engine);
- ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr);
+ hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE,
+ attributes, &media_engine);
+ ok(hr == MF_E_ATTRIBUTENOTFOUND, "IMFMediaEngineClassFactory_CreateInstance got %#x.\n", hr);
hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_OPM_HWND, NULL);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE, attributes, &media_engine);
- ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "IMFAttributes_SetUnknown failed: %#x.\n", hr);
+ hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE,
+ attributes, &media_engine);
+ ok(hr == MF_E_ATTRIBUTENOTFOUND, "IMFMediaEngineClassFactory_CreateInstance got %#x.\n", hr);
IMFAttributes_DeleteAllItems(attributes);
- hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, (IUnknown *)&notify->IMFMediaEngineNotify_iface);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, (IUnknown *)notify);
+ ok(hr == S_OK, "IMFAttributes_SetUnknown failed: %#x.\n", hr);
hr = IMFAttributes_SetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, DXGI_FORMAT_UNKNOWN);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "IMFAttributes_SetUINT32 failed: %#x.\n", hr);
EXPECT_REF(factory, 1);
- hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE, attributes, &media_engine);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE,
+ attributes, &media_engine);
+ ok(hr == S_OK, "IMFMediaEngineClassFactory_CreateInstance failed: %#x.\n", hr);
EXPECT_REF(factory, 1);
IMFMediaEngine_Release(media_engine);
IMFAttributes_Release(attributes);
IMFDXGIDeviceManager_Release(manager);
IMFMediaEngineClassFactory_Release(factory);
- IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
}
static void test_CreateInstance(void)
{
- struct media_engine_notify *notify;
- IMFMediaEngineEx *media_engine_ex;
+ struct media_engine_notify notify_impl = {{&media_engine_notify_vtbl}, 1};
+ IMFMediaEngineNotify *notify = &notify_impl.IMFMediaEngineNotify_iface;
IMFDXGIDeviceManager *manager;
IMFMediaEngine *media_engine;
IMFAttributes *attributes;
- IUnknown *unk;
UINT token;
HRESULT hr;
- BOOL ret;
-
- notify = create_callback();
hr = pMFCreateDXGIDeviceManager(&token, &manager);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Failed to create dxgi device manager, hr %#x.\n", hr);
hr = MFCreateAttributes(&attributes, 3);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Failed to create attributes, hr %#x.\n", hr);
hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE,
attributes, &media_engine);
- ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr);
+ ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr);
hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_OPM_HWND, NULL);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE,
attributes, &media_engine);
- ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr);
+ ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr);
IMFAttributes_DeleteAllItems(attributes);
- hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, (IUnknown *)&notify->IMFMediaEngineNotify_iface);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, (IUnknown *)notify);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
hr = IMFAttributes_SetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, DXGI_FORMAT_UNKNOWN);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_REAL_TIME_MODE
- | MF_MEDIA_ENGINE_WAITFORSTABLE_STATE, attributes, &media_engine);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
- check_interface(media_engine, &IID_IMFMediaEngine, TRUE);
-
- hr = IMFMediaEngine_QueryInterface(media_engine, &IID_IMFGetService, (void **)&unk);
- ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* supported since win10 */, "Unexpected hr %#lx.\n", hr);
- if (SUCCEEDED(hr))
- IUnknown_Release(unk);
-
- if (SUCCEEDED(IMFMediaEngine_QueryInterface(media_engine, &IID_IMFMediaEngineEx, (void **)&media_engine_ex)))
- {
- hr = IMFMediaEngineEx_GetRealTimeMode(media_engine_ex, &ret);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(ret, "Unexpected value.\n");
-
- hr = IMFMediaEngineEx_SetRealTimeMode(media_engine_ex, FALSE);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetRealTimeMode(media_engine_ex, &ret);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(!ret, "Unexpected value.\n");
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
- hr = IMFMediaEngineEx_SetRealTimeMode(media_engine_ex, TRUE);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetRealTimeMode(media_engine_ex, &ret);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(ret, "Unexpected value.\n");
-
- IMFMediaEngineEx_Release(media_engine_ex);
- }
+ hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE, attributes, &media_engine);
+ ok(hr == S_OK, "Failed to create media engine, hr %#x.\n", hr);
IMFMediaEngine_Release(media_engine);
IMFAttributes_Release(attributes);
IMFDXGIDeviceManager_Release(manager);
- IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
}
static void test_Shutdown(void)
{
- struct media_engine_notify *notify;
- IMFMediaEngineEx *media_engine_ex;
+ struct media_engine_notify notify_impl = {{&media_engine_notify_vtbl}, 1};
+ IMFMediaEngineNotify *callback = &notify_impl.IMFMediaEngineNotify_iface;
IMFMediaTimeRange *time_range;
IMFMediaEngine *media_engine;
- PROPVARIANT propvar;
- DWORD flags, cx, cy;
unsigned int state;
- UINT32 value;
+ DWORD cx, cy;
double val;
HRESULT hr;
BSTR str;
- BOOL ret;
- notify = create_callback();
-
- media_engine = create_media_engine(&notify->IMFMediaEngineNotify_iface);
+ media_engine = create_media_engine(callback);
hr = IMFMediaEngine_Shutdown(media_engine);
- ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr);
+ ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
hr = IMFMediaEngine_Shutdown(media_engine);
- ok(hr == MF_E_SHUTDOWN || broken(hr == S_OK) /* before win10 */, "Unexpected hr %#lx.\n", hr);
+ ok(hr == MF_E_SHUTDOWN || broken(hr == S_OK) /* before win10 */, "Unexpected hr %#x.\n", hr);
hr = IMFMediaEngine_SetSource(media_engine, NULL);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
hr = IMFMediaEngine_GetCurrentSource(media_engine, &str);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+todo_wine
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
state = IMFMediaEngine_GetNetworkState(media_engine);
ok(!state, "Unexpected state %d.\n", state);
@@ -353,26 +267,29 @@ static void test_Shutdown(void)
ok(!state, "Unexpected state %d.\n", state);
hr = IMFMediaEngine_SetPreload(media_engine, MF_MEDIA_ENGINE_PRELOAD_AUTOMATIC);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
state = IMFMediaEngine_GetPreload(media_engine);
ok(state == MF_MEDIA_ENGINE_PRELOAD_AUTOMATIC, "Unexpected state %d.\n", state);
hr = IMFMediaEngine_SetPreload(media_engine, 100);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
state = IMFMediaEngine_GetPreload(media_engine);
ok(state == 100, "Unexpected state %d.\n", state);
hr = IMFMediaEngine_GetBuffered(media_engine, &time_range);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+todo_wine
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
hr = IMFMediaEngine_Load(media_engine);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+todo_wine
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
str = SysAllocString(L"video/mp4");
hr = IMFMediaEngine_CanPlayType(media_engine, str, &state);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+todo_wine
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
SysFreeString(str);
state = IMFMediaEngine_GetReadyState(media_engine);
@@ -385,7 +302,8 @@ static void test_Shutdown(void)
ok(val == 0.0, "Unexpected time %f.\n", val);
hr = IMFMediaEngine_SetCurrentTime(media_engine, 1.0);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+todo_wine
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
val = IMFMediaEngine_GetStartTime(media_engine);
ok(val == 0.0, "Unexpected time %f.\n", val);
@@ -397,16 +315,18 @@ static void test_Shutdown(void)
ok(val == 1.0, "Unexpected rate %f.\n", val);
hr = IMFMediaEngine_SetDefaultPlaybackRate(media_engine, 2.0);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
val = IMFMediaEngine_GetPlaybackRate(media_engine);
ok(val == 1.0, "Unexpected rate %f.\n", val);
hr = IMFMediaEngine_GetPlayed(media_engine, &time_range);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+todo_wine
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
hr = IMFMediaEngine_GetSeekable(media_engine, &time_range);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+todo_wine
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
state = IMFMediaEngine_IsEnded(media_engine);
ok(!state, "Unexpected state %d.\n", state);
@@ -416,7 +336,7 @@ static void test_Shutdown(void)
ok(!state, "Unexpected state.\n");
hr = IMFMediaEngine_SetAutoPlay(media_engine, TRUE);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
state = IMFMediaEngine_GetAutoPlay(media_engine);
ok(!!state, "Unexpected state.\n");
@@ -426,28 +346,30 @@ static void test_Shutdown(void)
ok(!state, "Unexpected state.\n");
hr = IMFMediaEngine_SetLoop(media_engine, TRUE);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
state = IMFMediaEngine_GetLoop(media_engine);
ok(!!state, "Unexpected state.\n");
hr = IMFMediaEngine_Play(media_engine);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+todo_wine
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
hr = IMFMediaEngine_Pause(media_engine);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+todo_wine
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
state = IMFMediaEngine_GetMuted(media_engine);
ok(!state, "Unexpected state.\n");
hr = IMFMediaEngine_SetMuted(media_engine, TRUE);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
val = IMFMediaEngine_GetVolume(media_engine);
ok(val == 1.0, "Unexpected value %f.\n", val);
hr = IMFMediaEngine_SetVolume(media_engine, 2.0);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
state = IMFMediaEngine_HasVideo(media_engine);
ok(!state, "Unexpected state.\n");
@@ -456,59 +378,18 @@ static void test_Shutdown(void)
ok(!state, "Unexpected state.\n");
hr = IMFMediaEngine_GetNativeVideoSize(media_engine, &cx, &cy);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
hr = IMFMediaEngine_GetVideoAspectRatio(media_engine, &cx, &cy);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- if (SUCCEEDED(IMFMediaEngine_QueryInterface(media_engine, &IID_IMFMediaEngineEx, (void **)&media_engine_ex)))
- {
- hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine_ex, NULL, NULL);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetAudioStreamCategory(media_engine_ex, &value);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetAudioEndpointRole(media_engine_ex, &value);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_SetAudioStreamCategory(media_engine_ex, AudioCategory_ForegroundOnlyMedia);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_SetAudioEndpointRole(media_engine_ex, eConsole);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetResourceCharacteristics(media_engine_ex, NULL);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetResourceCharacteristics(media_engine_ex, &flags);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetRealTimeMode(media_engine_ex, NULL);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetRealTimeMode(media_engine_ex, &ret);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_SetRealTimeMode(media_engine_ex, TRUE);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetPresentationAttribute(media_engine_ex, &MF_PD_DURATION, &propvar);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetStreamAttribute(media_engine_ex, 0, &MF_SD_PROTECTED, &propvar);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
-
- IMFMediaEngineEx_Release(media_engine_ex);
- }
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
IMFMediaEngine_Release(media_engine);
- IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
}
static void test_Play(void)
{
- struct media_engine_notify *notify;
+ struct media_engine_notify notify_impl = {{&media_engine_notify_vtbl}, 1};
+ IMFMediaEngineNotify *callback = &notify_impl.IMFMediaEngineNotify_iface;
IMFMediaTimeRange *range, *range1;
IMFMediaEngine *media_engine;
LONGLONG pts;
@@ -516,18 +397,16 @@ static void test_Play(void)
HRESULT hr;
BOOL ret;
- notify = create_callback();
-
- media_engine = create_media_engine(&notify->IMFMediaEngineNotify_iface);
+ media_engine = create_media_engine(callback);
hr = IMFMediaEngine_GetBuffered(media_engine, &range);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFMediaEngine_GetBuffered(media_engine, &range1);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(range != range1, "Unexpected pointer.\n");
count = IMFMediaTimeRange_GetLength(range);
- ok(!count, "Unexpected count %lu.\n", count);
+ ok(!count, "Unexpected count %u.\n", count);
IMFMediaTimeRange_Release(range);
IMFMediaTimeRange_Release(range1);
@@ -536,30 +415,30 @@ static void test_Play(void)
ok(ret, "Unexpected state %d.\n", ret);
hr = IMFMediaEngine_OnVideoStreamTick(media_engine, NULL);
- ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
+ ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
pts = 0;
hr = IMFMediaEngine_OnVideoStreamTick(media_engine, &pts);
- ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
ok(pts == MINLONGLONG, "Unexpected timestamp.\n");
hr = IMFMediaEngine_Play(media_engine);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ret = IMFMediaEngine_IsPaused(media_engine);
ok(!ret, "Unexpected state %d.\n", ret);
hr = IMFMediaEngine_Play(media_engine);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFMediaEngine_Shutdown(media_engine);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFMediaEngine_OnVideoStreamTick(media_engine, NULL);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
hr = IMFMediaEngine_OnVideoStreamTick(media_engine, &pts);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
ret = IMFMediaEngine_IsPaused(media_engine);
ok(!ret, "Unexpected state %d.\n", ret);
@@ -567,34 +446,32 @@ static void test_Play(void)
IMFMediaEngine_Release(media_engine);
/* Play -> Pause */
- media_engine = create_media_engine(&notify->IMFMediaEngineNotify_iface);
+ media_engine = create_media_engine(callback);
hr = IMFMediaEngine_Play(media_engine);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ret = IMFMediaEngine_IsPaused(media_engine);
ok(!ret, "Unexpected state %d.\n", ret);
hr = IMFMediaEngine_Pause(media_engine);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ret = IMFMediaEngine_IsPaused(media_engine);
ok(!!ret, "Unexpected state %d.\n", ret);
IMFMediaEngine_Release(media_engine);
- IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
}
static void test_playback_rate(void)
{
- struct media_engine_notify *notify;
+ struct media_engine_notify notify_impl = {{&media_engine_notify_vtbl}, 1};
+ IMFMediaEngineNotify *callback = &notify_impl.IMFMediaEngineNotify_iface;
IMFMediaEngine *media_engine;
double rate;
HRESULT hr;
- notify = create_callback();
-
- media_engine = create_media_engine(&notify->IMFMediaEngineNotify_iface);
+ media_engine = create_media_engine(callback);
rate = IMFMediaEngine_GetDefaultPlaybackRate(media_engine);
ok(rate == 1.0, "Unexpected default rate.\n");
@@ -603,132 +480,127 @@ static void test_playback_rate(void)
ok(rate == 1.0, "Unexpected default rate.\n");
hr = IMFMediaEngine_SetPlaybackRate(media_engine, 0.0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
rate = IMFMediaEngine_GetPlaybackRate(media_engine);
ok(rate == 0.0, "Unexpected default rate.\n");
hr = IMFMediaEngine_SetDefaultPlaybackRate(media_engine, 0.0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
IMFMediaEngine_Release(media_engine);
- IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
}
static void test_mute(void)
{
- struct media_engine_notify *notify;
+ struct media_engine_notify notify_impl = {{&media_engine_notify_vtbl}, 1};
+ IMFMediaEngineNotify *callback = &notify_impl.IMFMediaEngineNotify_iface;
IMFMediaEngine *media_engine;
HRESULT hr;
BOOL ret;
- notify = create_callback();
-
- media_engine = create_media_engine(&notify->IMFMediaEngineNotify_iface);
+ media_engine = create_media_engine(callback);
ret = IMFMediaEngine_GetMuted(media_engine);
ok(!ret, "Unexpected state.\n");
hr = IMFMediaEngine_SetMuted(media_engine, TRUE);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ret = IMFMediaEngine_GetMuted(media_engine);
ok(ret, "Unexpected state.\n");
hr = IMFMediaEngine_Shutdown(media_engine);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ret = IMFMediaEngine_GetMuted(media_engine);
ok(ret, "Unexpected state.\n");
IMFMediaEngine_Release(media_engine);
- IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
}
static void test_error(void)
{
- struct media_engine_notify *notify;
+ struct media_engine_notify notify_impl = {{&media_engine_notify_vtbl}, 1};
+ IMFMediaEngineNotify *callback = &notify_impl.IMFMediaEngineNotify_iface;
IMFMediaEngine *media_engine;
IMFMediaError *eo, *eo2;
unsigned int code;
HRESULT hr;
- notify = create_callback();
-
- media_engine = create_media_engine(&notify->IMFMediaEngineNotify_iface);
+ media_engine = create_media_engine(callback);
eo = (void *)0xdeadbeef;
hr = IMFMediaEngine_GetError(media_engine, &eo);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(!eo, "Unexpected instance.\n");
hr = IMFMediaEngine_SetErrorCode(media_engine, MF_MEDIA_ENGINE_ERR_ENCRYPTED + 1);
- ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
hr = IMFMediaEngine_SetErrorCode(media_engine, MF_MEDIA_ENGINE_ERR_ABORTED);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
eo = NULL;
hr = IMFMediaEngine_GetError(media_engine, &eo);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(!!eo, "Unexpected instance.\n");
eo2 = NULL;
hr = IMFMediaEngine_GetError(media_engine, &eo2);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(eo2 != eo, "Unexpected instance.\n");
IMFMediaError_Release(eo2);
IMFMediaError_Release(eo);
hr = IMFMediaEngine_SetErrorCode(media_engine, MF_MEDIA_ENGINE_ERR_NOERROR);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
eo = (void *)0xdeadbeef;
hr = IMFMediaEngine_GetError(media_engine, &eo);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(!eo, "Unexpected instance.\n");
hr = IMFMediaEngine_Shutdown(media_engine);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
eo = (void *)0xdeadbeef;
hr = IMFMediaEngine_GetError(media_engine, &eo);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
ok(!eo, "Unexpected instance.\n");
hr = IMFMediaEngine_SetErrorCode(media_engine, MF_MEDIA_ENGINE_ERR_NOERROR);
- ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
IMFMediaEngine_Release(media_engine);
/* Error object. */
hr = IMFMediaEngineClassFactory_CreateError(factory, &eo);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Failed to create error object, hr %#x.\n", hr);
code = IMFMediaError_GetErrorCode(eo);
ok(code == MF_MEDIA_ENGINE_ERR_NOERROR, "Unexpected code %u.\n", code);
hr = IMFMediaError_GetExtendedErrorCode(eo);
- ok(hr == S_OK, "Unexpected code %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected code %#x.\n", hr);
hr = IMFMediaError_SetErrorCode(eo, MF_MEDIA_ENGINE_ERR_ENCRYPTED + 1);
- ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
hr = IMFMediaError_SetErrorCode(eo, MF_MEDIA_ENGINE_ERR_ABORTED);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
code = IMFMediaError_GetErrorCode(eo);
ok(code == MF_MEDIA_ENGINE_ERR_ABORTED, "Unexpected code %u.\n", code);
hr = IMFMediaError_SetExtendedErrorCode(eo, E_FAIL);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFMediaError_GetExtendedErrorCode(eo);
- ok(hr == E_FAIL, "Unexpected code %#lx.\n", hr);
+ ok(hr == E_FAIL, "Unexpected code %#x.\n", hr);
IMFMediaError_Release(eo);
- IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
}
static void test_time_range(void)
@@ -740,11 +612,11 @@ static void test_time_range(void)
BOOL ret;
hr = IMFMediaEngineClassFactory_CreateTimeRange(factory, &range);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
/* Empty ranges. */
hr = IMFMediaTimeRange_Clear(range);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ret = IMFMediaTimeRange_ContainsTime(range, 10.0);
ok(!ret, "Unexpected return value %d.\n", ret);
@@ -753,225 +625,81 @@ static void test_time_range(void)
ok(!count, "Unexpected range count.\n");
hr = IMFMediaTimeRange_GetStart(range, 0, &start);
- ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
- ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
/* Add a range. */
hr = IMFMediaTimeRange_AddRange(range, 10.0, 1.0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
count = IMFMediaTimeRange_GetLength(range);
ok(count == 1, "Unexpected range count.\n");
hr = IMFMediaTimeRange_GetStart(range, 0, &start);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(start == 10.0, "Unexpected start %.e.\n", start);
hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(end == 1.0, "Unexpected end %.e.\n", end);
hr = IMFMediaTimeRange_AddRange(range, 2.0, 3.0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+todo_wine
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
count = IMFMediaTimeRange_GetLength(range);
ok(count == 1, "Unexpected range count.\n");
hr = IMFMediaTimeRange_GetStart(range, 0, &start);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+todo_wine
ok(start == 2.0, "Unexpected start %.8e.\n", start);
hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+todo_wine
ok(end == 3.0, "Unexpected end %.8e.\n", end);
hr = IMFMediaTimeRange_AddRange(range, 10.0, 9.0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+todo_wine
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
count = IMFMediaTimeRange_GetLength(range);
+todo_wine
ok(count == 2, "Unexpected range count.\n");
hr = IMFMediaTimeRange_GetStart(range, 0, &start);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+todo_wine
ok(start == 2.0, "Unexpected start %.8e.\n", start);
hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+todo_wine
ok(end == 3.0, "Unexpected end %.8e.\n", end);
start = 0.0;
hr = IMFMediaTimeRange_GetStart(range, 1, &start);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(start == 10.0, "Unexpected start %.8e.\n", start);
-
- hr = IMFMediaTimeRange_GetEnd(range, 1, &end);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(end == 9.0, "Unexpected end %.8e.\n", end);
-
- hr = IMFMediaTimeRange_AddRange(range, 2.0, 9.1);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
- count = IMFMediaTimeRange_GetLength(range);
- ok(count == 2, "Unexpected range count.\n");
-
- hr = IMFMediaTimeRange_GetStart(range, 0, &start);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(start == 2.0, "Unexpected start %.8e.\n", start);
-
- hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(end == 9.1, "Unexpected end %.8e.\n", end);
-
- hr = IMFMediaTimeRange_GetStart(range, 1, &start);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+todo_wine {
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(start == 10.0, "Unexpected start %.8e.\n", start);
-
+}
hr = IMFMediaTimeRange_GetEnd(range, 1, &end);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+todo_wine {
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(end == 9.0, "Unexpected end %.8e.\n", end);
-
- hr = IMFMediaTimeRange_AddRange(range, 8.5, 2.5);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
- count = IMFMediaTimeRange_GetLength(range);
- ok(count == 2, "Unexpected range count.\n");
-
- hr = IMFMediaTimeRange_GetStart(range, 0, &start);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(start == 2.0, "Unexpected start %.8e.\n", start);
-
- hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(end == 9.1, "Unexpected end %.8e.\n", end);
-
- hr = IMFMediaTimeRange_AddRange(range, 20.0, 20.0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
- count = IMFMediaTimeRange_GetLength(range);
- ok(count == 3, "Unexpected range count.\n");
-
+}
hr = IMFMediaTimeRange_Clear(range);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
count = IMFMediaTimeRange_GetLength(range);
ok(!count, "Unexpected range count.\n");
- /* Intersect */
- hr = IMFMediaTimeRange_AddRange(range, 5.0, 10.0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaTimeRange_AddRange(range, 6.0, 12.0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaTimeRange_GetStart(range, 0, &start);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(start == 5.0, "Unexpected start %.8e.\n", start);
-
- hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(end == 12.0, "Unexpected end %.8e.\n", end);
-
- count = IMFMediaTimeRange_GetLength(range);
- ok(count == 1, "Unexpected range count.\n");
-
- hr = IMFMediaTimeRange_AddRange(range, 4.0, 6.0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
- count = IMFMediaTimeRange_GetLength(range);
- ok(count == 1, "Unexpected range count.\n");
-
- hr = IMFMediaTimeRange_GetStart(range, 0, &start);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(start == 4.0, "Unexpected start %.8e.\n", start);
-
- hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(end == 12.0, "Unexpected end %.8e.\n", end);
-
- hr = IMFMediaTimeRange_AddRange(range, 5.0, 3.0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
- count = IMFMediaTimeRange_GetLength(range);
- ok(count == 1, "Unexpected range count.\n");
-
- hr = IMFMediaTimeRange_GetStart(range, 0, &start);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(start == 4.0, "Unexpected start %.8e.\n", start);
-
- hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(end == 12.0, "Unexpected end %.8e.\n", end);
-
IMFMediaTimeRange_Release(range);
}
-static void test_SetSourceFromByteStream(void)
-{
- struct media_engine_notify *notify;
- IMFMediaEngineEx *media_engine;
- PROPVARIANT propvar;
- DWORD flags;
- HRESULT hr;
-
- notify = create_callback();
-
- media_engine = create_media_engine_ex(&notify->IMFMediaEngineNotify_iface);
- if (!media_engine)
- {
- win_skip("IMFMediaEngineEx is not supported.\n");
- IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
- return;
- }
-
- hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine, NULL, NULL);
- ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetResourceCharacteristics(media_engine, NULL);
- ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetResourceCharacteristics(media_engine, &flags);
- ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetPresentationAttribute(media_engine, &MF_PD_DURATION, &propvar);
- ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
-
- hr = IMFMediaEngineEx_GetStreamAttribute(media_engine, 0, &MF_SD_PROTECTED, &propvar);
- ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
-
- IMFMediaEngineEx_Release(media_engine);
- IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
-}
-
-static void test_audio_configuration(void)
-{
- struct media_engine_notify *notify;
- IMFMediaEngineEx *media_engine;
- UINT32 value;
- HRESULT hr;
-
- notify = create_callback();
-
- media_engine = create_media_engine_ex(&notify->IMFMediaEngineNotify_iface);
- if (!media_engine)
- {
- IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
- return;
- }
-
- hr = IMFMediaEngineEx_GetAudioStreamCategory(media_engine, &value);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(value == AudioCategory_Other, "Unexpected value %u.\n", value);
-
- hr = IMFMediaEngineEx_GetAudioEndpointRole(media_engine, &value);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(value == eMultimedia, "Unexpected value %u.\n", value);
-
- IMFMediaEngineEx_Release(media_engine);
- IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
-}
-
START_TEST(mfmediaengine)
{
HRESULT hr;
@@ -990,7 +718,7 @@ START_TEST(mfmediaengine)
init_functions();
hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
- ok(hr == S_OK, "MFStartup failed: %#lx.\n", hr);
+ ok(hr == S_OK, "MFStartup failed: %#x.\n", hr);
test_factory();
test_CreateInstance();
@@ -1000,8 +728,6 @@ START_TEST(mfmediaengine)
test_mute();
test_error();
test_time_range();
- test_SetSourceFromByteStream();
- test_audio_configuration();
IMFMediaEngineClassFactory_Release(factory);
diff --git a/dlls/mfplat/Makefile.in b/dlls/mfplat/Makefile.in
index 4515d652c58..79af7650de6 100644
--- wine/dlls/mfplat/Makefile.in
+++ wine/dlls/mfplat/Makefile.in
@@ -1,7 +1,7 @@
+EXTRADEFS = -DWINE_NO_LONG_TYPES
MODULE = mfplat.dll
IMPORTLIB = mfplat
-IMPORTS = advapi32 ole32 mfuuid propsys rtworkq kernelbase
-DELAYIMPORTS = bcrypt
+IMPORTS = advapi32 ole32 mfuuid propsys rtworkq
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/mfplat/aac_decoder.c b/dlls/mfplat/aac_decoder.c
new file mode 100644
index 00000000000..97f2824039d
--- /dev/null
+++ wine/dlls/mfplat/aac_decoder.c
@@ -0,0 +1,620 @@
+/* AAC Decoder Transform
+ *
+ * Copyright 2022 Rémi Bernon for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "gst_private.h"
+
+#include "mfapi.h"
+#include "mferror.h"
+#include "mfobjects.h"
+#include "mftransform.h"
+#include "wmcodecdsp.h"
+
+#include "wine/debug.h"
+#include "wine/heap.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+static const GUID *aac_decoder_input_types[] =
+{
+ &MFAudioFormat_AAC,
+};
+static const GUID *aac_decoder_output_types[] =
+{
+ &MFAudioFormat_PCM,
+ &MFAudioFormat_Float,
+};
+
+struct aac_decoder
+{
+ IMFTransform IMFTransform_iface;
+ LONG refcount;
+ IMFMediaType *input_type;
+ IMFMediaType *output_type;
+
+ IMFSample *input_sample;
+ struct wg_transform *wg_transform;
+};
+
+static struct aac_decoder *impl_from_IMFTransform(IMFTransform *iface)
+{
+ return CONTAINING_RECORD(iface, struct aac_decoder, IMFTransform_iface);
+}
+
+static void try_create_wg_transform(struct aac_decoder *decoder)
+{
+ struct wg_encoded_format input_format;
+ struct wg_format output_format;
+
+ if (!decoder->input_type || !decoder->output_type)
+ return;
+
+ if (decoder->wg_transform)
+ wg_transform_destroy(decoder->wg_transform);
+
+ mf_media_type_to_wg_encoded_format(decoder->input_type, &input_format);
+ if (input_format.encoded_type == WG_ENCODED_TYPE_UNKNOWN)
+ return;
+
+ mf_media_type_to_wg_format(decoder->output_type, &output_format);
+ if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
+ return;
+
+ decoder->wg_transform = wg_transform_create(&input_format, &output_format);
+ if (!decoder->wg_transform)
+ WARN("Failed to create wg_transform.\n");
+}
+
+static HRESULT WINAPI aac_decoder_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
+{
+ struct aac_decoder *decoder = impl_from_IMFTransform(iface);
+
+ TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+ if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IMFTransform))
+ *out = &decoder->IMFTransform_iface;
+ else
+ {
+ *out = NULL;
+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown *)*out);
+ return S_OK;
+}
+
+static ULONG WINAPI aac_decoder_AddRef(IMFTransform *iface)
+{
+ struct aac_decoder *decoder = impl_from_IMFTransform(iface);
+ ULONG refcount = InterlockedIncrement(&decoder->refcount);
+
+ TRACE("iface %p increasing refcount to %u.\n", decoder, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI aac_decoder_Release(IMFTransform *iface)
+{
+ struct aac_decoder *decoder = impl_from_IMFTransform(iface);
+ ULONG refcount = InterlockedDecrement(&decoder->refcount);
+
+ TRACE("iface %p decreasing refcount to %u.\n", decoder, refcount);
+
+ if (!refcount)
+ {
+ if (decoder->input_sample)
+ IMFSample_Release(decoder->input_sample);
+ if (decoder->wg_transform)
+ wg_transform_destroy(decoder->wg_transform);
+ if (decoder->input_type)
+ IMFMediaType_Release(decoder->input_type);
+ if (decoder->output_type)
+ IMFMediaType_Release(decoder->output_type);
+ free(decoder);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI aac_decoder_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum,
+ DWORD *output_minimum, DWORD *output_maximum)
+{
+ FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p stub!\n",
+ iface, input_minimum, input_maximum, output_minimum, output_maximum);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
+{
+ FIXME("iface %p, inputs %p, outputs %p stub!\n", iface, inputs, outputs);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
+ DWORD output_size, DWORD *outputs)
+{
+ FIXME("iface %p, input_size %u, inputs %p, output_size %u, outputs %p stub!\n",
+ iface, input_size, inputs, output_size, outputs);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
+{
+ struct aac_decoder *decoder = impl_from_IMFTransform(iface);
+ UINT32 block_alignment;
+ HRESULT hr;
+
+ TRACE("iface %p, id %u, info %p.\n", iface, id, info);
+
+ if (!decoder->input_type || !decoder->output_type)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment)))
+ return hr;
+
+ info->hnsMaxLatency = 0;
+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES|MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
+ |MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE|MFT_INPUT_STREAM_HOLDS_BUFFERS;
+ info->cbSize = 0;
+ info->cbMaxLookahead = 0;
+ info->cbAlignment = 0;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI aac_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
+{
+ struct aac_decoder *decoder = impl_from_IMFTransform(iface);
+ UINT32 channel_count, block_alignment;
+ HRESULT hr;
+
+ TRACE("iface %p, id %u, info %p.\n", iface, id, info);
+
+ if (!decoder->input_type || !decoder->output_type)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->output_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count)))
+ return hr;
+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment)))
+ return hr;
+
+ info->dwFlags = 0;
+ info->cbSize = 0x1800 * block_alignment * channel_count;
+ info->cbAlignment = 0;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI aac_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
+{
+ FIXME("iface %p, attributes %p stub!\n", iface, attributes);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ FIXME("iface %p, id %u, attributes %p stub!\n", iface, id, attributes);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_GetOutputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ FIXME("iface %p, id %u, attributes %p stub!\n", iface, id, attributes);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_DeleteInputStream(IMFTransform *iface, DWORD id)
+{
+ FIXME("iface %p, id %u stub!\n", iface, id);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
+{
+ FIXME("iface %p, streams %u, ids %p stub!\n", iface, streams, ids);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ FIXME("iface %p, id %u, index %u, type %p stub!\n", iface, id, index, type);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ UINT32 channel_count, sample_size, sample_rate, block_alignment;
+ struct aac_decoder *decoder = impl_from_IMFTransform(iface);
+ IMFMediaType *media_type;
+ const GUID *output_type;
+ HRESULT hr;
+
+ TRACE("iface %p, id %u, index %u, type %p.\n", iface, id, index, type);
+
+ if (!decoder->input_type)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ *type = NULL;
+
+ if (index >= ARRAY_SIZE(aac_decoder_output_types))
+ return MF_E_NO_MORE_TYPES;
+ index = ARRAY_SIZE(aac_decoder_output_types) - index - 1;
+ output_type = aac_decoder_output_types[index];
+
+ if (FAILED(hr = MFCreateMediaType(&media_type)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio)))
+ goto done;
+ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type)))
+ goto done;
+
+ if (IsEqualGUID(output_type, &MFAudioFormat_Float))
+ sample_size = 32;
+ else if (IsEqualGUID(output_type, &MFAudioFormat_PCM))
+ sample_size = 16;
+ else
+ {
+ FIXME("Subtype %s not implemented!\n", debugstr_guid(output_type));
+ hr = E_NOTIMPL;
+ goto done;
+ }
+
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size)))
+ goto done;
+
+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count)))
+ goto done;
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channel_count)))
+ goto done;
+
+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &sample_rate)))
+ goto done;
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, sample_rate)))
+ goto done;
+
+ block_alignment = sample_size * channel_count / 8;
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, block_alignment)))
+ goto done;
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, sample_rate * block_alignment)))
+ goto done;
+
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1)))
+ goto done;
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1)))
+ goto done;
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1)))
+ goto done;
+
+done:
+ if (SUCCEEDED(hr))
+ IMFMediaType_AddRef((*type = media_type));
+
+ IMFMediaType_Release(media_type);
+ return hr;
+}
+
+static HRESULT WINAPI aac_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ struct aac_decoder *decoder = impl_from_IMFTransform(iface);
+ MF_ATTRIBUTE_TYPE item_type;
+ GUID major, subtype;
+ HRESULT hr;
+ ULONG i;
+
+ TRACE("iface %p, id %u, type %p, flags %#x.\n", iface, id, type, flags);
+
+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ return hr;
+
+ if (!IsEqualGUID(&major, &MFMediaType_Audio))
+ return MF_E_INVALIDMEDIATYPE;
+
+ for (i = 0; i < ARRAY_SIZE(aac_decoder_input_types); ++i)
+ if (IsEqualGUID(&subtype, aac_decoder_input_types[i]))
+ break;
+ if (i == ARRAY_SIZE(aac_decoder_input_types))
+ return MF_E_INVALIDMEDIATYPE;
+
+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_USER_DATA, &item_type)) ||
+ item_type != MF_ATTRIBUTE_BLOB)
+ return MF_E_INVALIDMEDIATYPE;
+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &item_type)) ||
+ item_type != MF_ATTRIBUTE_UINT32)
+ return MF_E_INVALIDMEDIATYPE;
+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) ||
+ item_type != MF_ATTRIBUTE_UINT32)
+ return MF_E_INVALIDMEDIATYPE;
+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_NUM_CHANNELS, &item_type)) ||
+ item_type != MF_ATTRIBUTE_UINT32)
+ return MF_E_INVALIDMEDIATYPE;
+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &item_type)) ||
+ item_type != MF_ATTRIBUTE_UINT32)
+ return MF_E_INVALIDMEDIATYPE;
+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &item_type)) ||
+ item_type != MF_ATTRIBUTE_UINT32)
+ return MF_E_INVALIDMEDIATYPE;
+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, &item_type)) ||
+ item_type != MF_ATTRIBUTE_UINT32)
+ return MF_E_INVALIDMEDIATYPE;
+
+ if (!decoder->input_type && FAILED(hr = MFCreateMediaType(&decoder->input_type)))
+ return hr;
+
+ if (decoder->output_type)
+ {
+ IMFMediaType_Release(decoder->output_type);
+ decoder->output_type = NULL;
+ }
+
+ return IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->input_type);
+}
+
+static HRESULT WINAPI aac_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ struct aac_decoder *decoder = impl_from_IMFTransform(iface);
+ MF_ATTRIBUTE_TYPE item_type;
+ ULONG i, sample_size;
+ GUID major, subtype;
+ HRESULT hr;
+
+ TRACE("iface %p, id %u, type %p, flags %#x.\n", iface, id, type, flags);
+
+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ return hr;
+
+ if (!IsEqualGUID(&major, &MFMediaType_Audio))
+ return MF_E_INVALIDMEDIATYPE;
+
+ for (i = 0; i < ARRAY_SIZE(aac_decoder_output_types); ++i)
+ if (IsEqualGUID(&subtype, aac_decoder_output_types[i]))
+ break;
+ if (i == ARRAY_SIZE(aac_decoder_output_types))
+ return MF_E_INVALIDMEDIATYPE;
+
+ if (IsEqualGUID(&subtype, &MFAudioFormat_Float))
+ sample_size = 32;
+ else if (IsEqualGUID(&subtype, &MFAudioFormat_PCM))
+ sample_size = 16;
+ else
+ {
+ FIXME("Subtype %s not implemented!\n", debugstr_guid(&subtype));
+ hr = E_NOTIMPL;
+ return hr;
+ }
+
+ if (FAILED(IMFMediaType_SetUINT32(decoder->input_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size)))
+ return MF_E_INVALIDMEDIATYPE;
+
+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &item_type)) ||
+ item_type != MF_ATTRIBUTE_UINT32)
+ return MF_E_INVALIDMEDIATYPE;
+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &item_type)) ||
+ item_type != MF_ATTRIBUTE_UINT32)
+ return MF_E_INVALIDMEDIATYPE;
+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_NUM_CHANNELS, &item_type)) ||
+ item_type != MF_ATTRIBUTE_UINT32)
+ return MF_E_INVALIDMEDIATYPE;
+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) ||
+ item_type != MF_ATTRIBUTE_UINT32)
+ return MF_E_INVALIDMEDIATYPE;
+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &item_type)) ||
+ item_type != MF_ATTRIBUTE_UINT32)
+ return MF_E_INVALIDMEDIATYPE;
+
+ if (!decoder->output_type && FAILED(hr = MFCreateMediaType(&decoder->output_type)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type)))
+ return hr;
+
+ try_create_wg_transform(decoder);
+ return S_OK;
+}
+
+static HRESULT WINAPI aac_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ FIXME("iface %p, id %u, type %p stub!\n", iface, id, type);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ FIXME("iface %p, id %u, type %p stub!\n", iface, id, type);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
+{
+ FIXME("iface %p, id %u, flags %p stub!\n", iface, id, flags);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags)
+{
+ FIXME("iface %p, flags %p stub!\n", iface, flags);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
+{
+ FIXME("iface %p, lower %s, upper %s stub!\n", iface,
+ wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper));
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
+{
+ FIXME("iface %p, id %u, event %p stub!\n", iface, id, event);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI aac_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
+{
+ FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param);
+ return S_OK;
+}
+
+static HRESULT WINAPI aac_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
+{
+ struct aac_decoder *decoder = impl_from_IMFTransform(iface);
+ IMFMediaBuffer *media_buffer;
+ MFT_INPUT_STREAM_INFO info;
+ UINT32 buffer_size;
+ BYTE *buffer;
+ HRESULT hr;
+
+ TRACE("iface %p, id %u, sample %p, flags %#x.\n", iface, id, sample, flags);
+
+ if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info)))
+ return hr;
+
+ if (!decoder->wg_transform)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ if (decoder->input_sample)
+ return MF_E_NOTACCEPTING;
+
+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, &buffer_size)))
+ goto done;
+
+ if (SUCCEEDED(hr = wg_transform_push_data(decoder->wg_transform, buffer, buffer_size)))
+ IMFSample_AddRef((decoder->input_sample = sample));
+
+ IMFMediaBuffer_Unlock(media_buffer);
+
+done:
+ IMFMediaBuffer_Release(media_buffer);
+ return hr;
+}
+
+static HRESULT WINAPI aac_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
+{
+ struct aac_decoder *decoder = impl_from_IMFTransform(iface);
+ struct wg_sample wg_sample = {0};
+ IMFMediaBuffer *media_buffer;
+ MFT_OUTPUT_STREAM_INFO info;
+ HRESULT hr;
+
+ TRACE("iface %p, flags %#x, count %u, samples %p, status %p.\n", iface, flags, count, samples, status);
+
+ if (count > 1)
+ {
+ FIXME("Not implemented count %u\n", count);
+ return E_NOTIMPL;
+ }
+
+ if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info)))
+ return hr;
+
+ if (!decoder->wg_transform)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ *status = 0;
+ samples[0].dwStatus = 0;
+ if (!samples[0].pSample)
+ {
+ samples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE;
+ return MF_E_TRANSFORM_NEED_MORE_INPUT;
+ }
+
+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &media_buffer)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &wg_sample.data, &wg_sample.size, NULL)))
+ goto done;
+
+ if (wg_sample.size < info.cbSize)
+ hr = MF_E_BUFFERTOOSMALL;
+ else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample)))
+ {
+ if (wg_sample.flags & WG_SAMPLE_FLAG_INCOMPLETE)
+ samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE;
+ }
+ else
+ {
+ if (decoder->input_sample)
+ IMFSample_Release(decoder->input_sample);
+ decoder->input_sample = NULL;
+ }
+
+ IMFMediaBuffer_Unlock(media_buffer);
+
+done:
+ IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size);
+ IMFMediaBuffer_Release(media_buffer);
+ return hr;
+}
+
+static const IMFTransformVtbl aac_decoder_vtbl =
+{
+ aac_decoder_QueryInterface,
+ aac_decoder_AddRef,
+ aac_decoder_Release,
+ aac_decoder_GetStreamLimits,
+ aac_decoder_GetStreamCount,
+ aac_decoder_GetStreamIDs,
+ aac_decoder_GetInputStreamInfo,
+ aac_decoder_GetOutputStreamInfo,
+ aac_decoder_GetAttributes,
+ aac_decoder_GetInputStreamAttributes,
+ aac_decoder_GetOutputStreamAttributes,
+ aac_decoder_DeleteInputStream,
+ aac_decoder_AddInputStreams,
+ aac_decoder_GetInputAvailableType,
+ aac_decoder_GetOutputAvailableType,
+ aac_decoder_SetInputType,
+ aac_decoder_SetOutputType,
+ aac_decoder_GetInputCurrentType,
+ aac_decoder_GetOutputCurrentType,
+ aac_decoder_GetInputStatus,
+ aac_decoder_GetOutputStatus,
+ aac_decoder_SetOutputBounds,
+ aac_decoder_ProcessEvent,
+ aac_decoder_ProcessMessage,
+ aac_decoder_ProcessInput,
+ aac_decoder_ProcessOutput,
+};
+
+HRESULT aac_decoder_create(REFIID riid, void **ret)
+{
+ struct aac_decoder *decoder;
+
+ TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
+
+ if (!(decoder = calloc(1, sizeof(*decoder))))
+ return E_OUTOFMEMORY;
+
+ decoder->IMFTransform_iface.lpVtbl = &aac_decoder_vtbl;
+ decoder->refcount = 1;
+
+ *ret = &decoder->IMFTransform_iface;
+ TRACE("Created decoder %p\n", *ret);
+ return S_OK;
+}
diff --git a/dlls/mfplat/audioconvert.c b/dlls/mfplat/audioconvert.c
new file mode 100644
index 00000000000..2e16c9c78f5
--- /dev/null
+++ wine/dlls/mfplat/audioconvert.c
@@ -0,0 +1,910 @@
+/* GStreamer Audio Converter
+ *
+ * Copyright 2020 Derek Lesho
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "gst_private.h"
+
+#include "mfapi.h"
+#include "mferror.h"
+#include "ks.h"
+#include "ksmedia.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+struct audio_converter
+{
+ IMFTransform IMFTransform_iface;
+ LONG refcount;
+ IMFMediaType *input_type;
+ IMFMediaType *output_type;
+ CRITICAL_SECTION cs;
+ BOOL buffer_inflight;
+ LONGLONG buffer_pts, buffer_dur;
+ struct wg_parser *parser;
+ struct wg_parser_stream *stream;
+ IMFAttributes *attributes, *output_attributes;
+};
+
+static struct audio_converter *impl_audio_converter_from_IMFTransform(IMFTransform *iface)
+{
+ return CONTAINING_RECORD(iface, struct audio_converter, IMFTransform_iface);
+}
+
+static HRESULT WINAPI audio_converter_QueryInterface(IMFTransform *iface, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFTransform) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IMFTransform_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI audio_converter_AddRef(IMFTransform *iface)
+{
+ struct audio_converter *transform = impl_audio_converter_from_IMFTransform(iface);
+ ULONG refcount = InterlockedIncrement(&transform->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI audio_converter_Release(IMFTransform *iface)
+{
+ struct audio_converter *transform = impl_audio_converter_from_IMFTransform(iface);
+ ULONG refcount = InterlockedDecrement(&transform->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ transform->cs.DebugInfo->Spare[0] = 0;
+ DeleteCriticalSection(&transform->cs);
+ if (transform->attributes)
+ IMFAttributes_Release(transform->attributes);
+ if (transform->output_attributes)
+ IMFAttributes_Release(transform->output_attributes);
+ if (transform->stream)
+ wg_parser_disconnect(transform->parser);
+ if (transform->parser)
+ wg_parser_destroy(transform->parser);
+ free(transform);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI audio_converter_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum,
+ DWORD *output_minimum, DWORD *output_maximum)
+{
+ TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum);
+
+ *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI audio_converter_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
+{
+ TRACE("%p, %p, %p.\n", iface, inputs, outputs);
+
+ *inputs = *outputs = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI audio_converter_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
+ DWORD output_size, DWORD *outputs)
+{
+ TRACE("%p %u %p %u %p.\n", iface, input_size, inputs, output_size, outputs);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI audio_converter_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
+{
+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface);
+
+ TRACE("%p %u %p.\n", iface, id, info);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF;
+ info->cbMaxLookahead = 0;
+ info->cbAlignment = 0;
+ info->hnsMaxLatency = 0;
+ info->cbSize = 0;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (converter->input_type)
+ IMFMediaType_GetUINT32(converter->input_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &info->cbSize);
+
+ LeaveCriticalSection(&converter->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI audio_converter_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
+{
+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface);
+
+ TRACE("%p %u %p.\n", iface, id, info);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ info->dwFlags = MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES | MFT_OUTPUT_STREAM_WHOLE_SAMPLES;
+ info->cbAlignment = 0;
+ info->cbSize = 0;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (converter->output_type)
+ IMFMediaType_GetUINT32(converter->output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &info->cbSize);
+
+ LeaveCriticalSection(&converter->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI audio_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
+{
+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface);
+
+ TRACE("%p, %p.\n", iface, attributes);
+
+ *attributes = converter->attributes;
+ IMFAttributes_AddRef(*attributes);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI audio_converter_GetInputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ FIXME("%p, %u, %p.\n", iface, id, attributes);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI audio_converter_GetOutputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface);
+
+ TRACE("%p, %u, %p.\n", iface, id, attributes);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ *attributes = converter->output_attributes;
+ IMFAttributes_AddRef(*attributes);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI audio_converter_DeleteInputStream(IMFTransform *iface, DWORD id)
+{
+ TRACE("%p, %u.\n", iface, id);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI audio_converter_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
+{
+ TRACE("%p, %u, %p.\n", iface, streams, ids);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI audio_converter_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ IMFMediaType *ret;
+ HRESULT hr;
+
+ TRACE("%p, %u, %u, %p.\n", iface, id, index, type);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (index >= 2)
+ return MF_E_NO_MORE_TYPES;
+
+ if (FAILED(hr = MFCreateMediaType(&ret)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaType_SetGUID(ret, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio)))
+ {
+ IMFMediaType_Release(ret);
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_SetGUID(ret, &MF_MT_SUBTYPE, index ? &MFAudioFormat_Float : &MFAudioFormat_PCM)))
+ {
+ IMFMediaType_Release(ret);
+ return hr;
+ }
+
+ *type = ret;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI audio_converter_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ IMFMediaType *output_type;
+ HRESULT hr;
+
+ static const struct
+ {
+ const GUID *subtype;
+ DWORD depth;
+ }
+ formats[] =
+ {
+ {&MFAudioFormat_PCM, 16},
+ {&MFAudioFormat_PCM, 24},
+ {&MFAudioFormat_PCM, 32},
+ {&MFAudioFormat_Float, 32},
+ };
+
+ static const DWORD rates[] = {44100, 48000};
+ static const DWORD channel_cnts[] = {1, 2, 6};
+ const GUID *subtype;
+ DWORD rate, channels, bps;
+
+ TRACE("%p, %u, %u, %p.\n", iface, id, index, type);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (index >= ARRAY_SIZE(formats) * 2/*rates*/ * 3/*layouts*/)
+ return MF_E_NO_MORE_TYPES;
+
+ if (FAILED(hr = MFCreateMediaType(&output_type)))
+ return hr;
+
+ subtype = formats[index / 6].subtype;
+ bps = formats[index / 6].depth;
+ rate = rates[index % 2];
+ channels = channel_cnts[(index / 2) % 3];
+
+ if (FAILED(hr = IMFMediaType_SetGUID(output_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio)))
+ goto fail;
+ if (FAILED(hr = IMFMediaType_SetGUID(output_type, &MF_MT_SUBTYPE, subtype)))
+ goto fail;
+ if (FAILED(hr = IMFMediaType_SetUINT32(output_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, rate)))
+ goto fail;
+ if (FAILED(hr = IMFMediaType_SetUINT32(output_type, &MF_MT_AUDIO_NUM_CHANNELS, channels)))
+ goto fail;
+ if (FAILED(hr = IMFMediaType_SetUINT32(output_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, bps)))
+ goto fail;
+
+ if (FAILED(hr = IMFMediaType_SetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, channels * bps / 8)))
+ goto fail;
+ if (FAILED(hr = IMFMediaType_SetUINT32(output_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, rate * channels * bps / 8)))
+ goto fail;
+ if (FAILED(hr = IMFMediaType_SetUINT32(output_type, &MF_MT_AUDIO_CHANNEL_MASK,
+ channels == 1 ? KSAUDIO_SPEAKER_MONO :
+ channels == 2 ? KSAUDIO_SPEAKER_STEREO :
+ /*channels == 6*/ KSAUDIO_SPEAKER_5POINT1)))
+ goto fail;
+ if (FAILED(hr = IMFMediaType_SetUINT32(output_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE)))
+ goto fail;
+
+ *type = output_type;
+
+ return S_OK;
+fail:
+ IMFMediaType_Release(output_type);
+ return hr;
+}
+
+static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ GUID major_type, subtype;
+ struct wg_format format;
+ DWORD unused;
+ HRESULT hr;
+
+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface);
+
+ TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (!type)
+ {
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ return S_OK;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (converter->input_type)
+ {
+ if (converter->stream)
+ {
+ wg_parser_disconnect(converter->parser);
+ converter->stream = NULL;
+ }
+ IMFMediaType_Release(converter->input_type);
+ converter->input_type = NULL;
+ }
+
+ LeaveCriticalSection(&converter->cs);
+
+ return S_OK;
+ }
+
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type)))
+ return MF_E_INVALIDTYPE;
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ return MF_E_INVALIDTYPE;
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &unused)))
+ return MF_E_INVALIDTYPE;
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &unused)))
+ return MF_E_INVALIDTYPE;
+ if (IsEqualGUID(&subtype, &MFAudioFormat_PCM) && FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &unused)))
+ return MF_E_INVALIDTYPE;
+
+ if (!(IsEqualGUID(&major_type, &MFMediaType_Audio)))
+ return MF_E_INVALIDTYPE;
+
+ if (!IsEqualGUID(&subtype, &MFAudioFormat_PCM) && !IsEqualGUID(&subtype, &MFAudioFormat_Float))
+ return MF_E_INVALIDTYPE;
+
+ mf_media_type_to_wg_format(type, &format);
+ if (!format.major_type)
+ return MF_E_INVALIDTYPE;
+
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ return S_OK;
+
+ EnterCriticalSection(&converter->cs);
+
+ hr = S_OK;
+
+ if (!converter->input_type)
+ hr = MFCreateMediaType(&converter->input_type);
+
+ if (SUCCEEDED(hr))
+ hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->input_type);
+
+ if (FAILED(hr))
+ {
+ IMFMediaType_Release(converter->input_type);
+ converter->input_type = NULL;
+ }
+
+ if (converter->stream)
+ {
+ wg_parser_disconnect(converter->parser);
+ converter->stream = NULL;
+ }
+
+ if (converter->input_type && converter->output_type)
+ {
+ struct wg_format output_format;
+ mf_media_type_to_wg_format(converter->output_type, &output_format);
+
+ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format, NULL)))
+ converter->stream = wg_parser_get_stream(converter->parser, 0);
+ }
+
+ LeaveCriticalSection(&converter->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface);
+ GUID major_type, subtype;
+ struct wg_format format;
+ DWORD unused;
+ HRESULT hr;
+
+ TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (!type)
+ {
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ return S_OK;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (converter->output_type)
+ {
+ if (converter->stream)
+ {
+ wg_parser_disconnect(converter->parser);
+ converter->stream = NULL;
+ }
+ IMFMediaType_Release(converter->output_type);
+ converter->output_type = NULL;
+ }
+
+ LeaveCriticalSection(&converter->cs);
+
+ return S_OK;
+ }
+
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type)))
+ return MF_E_INVALIDTYPE;
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ return MF_E_INVALIDTYPE;
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &unused)))
+ return MF_E_INVALIDTYPE;
+ if (IsEqualGUID(&subtype, &MFAudioFormat_PCM) && FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &unused)))
+ return MF_E_INVALIDTYPE;
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &unused)))
+ return MF_E_INVALIDTYPE;
+
+ if (!(IsEqualGUID(&major_type, &MFMediaType_Audio)))
+ return MF_E_INVALIDTYPE;
+
+ if (!IsEqualGUID(&subtype, &MFAudioFormat_PCM) && !IsEqualGUID(&subtype, &MFAudioFormat_Float))
+ return MF_E_INVALIDTYPE;
+
+ mf_media_type_to_wg_format(type, &format);
+ if (!format.major_type)
+ return MF_E_INVALIDTYPE;
+
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ return S_OK;
+
+ EnterCriticalSection(&converter->cs);
+
+ hr = S_OK;
+
+ if (!converter->output_type)
+ hr = MFCreateMediaType(&converter->output_type);
+
+ if (SUCCEEDED(hr))
+ hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->output_type);
+
+ if (FAILED(hr))
+ {
+ IMFMediaType_Release(converter->output_type);
+ converter->output_type = NULL;
+ }
+
+ if (converter->stream)
+ {
+ wg_parser_disconnect(converter->parser);
+ converter->stream = NULL;
+ }
+
+ if (converter->input_type && converter->output_type)
+ {
+ struct wg_format input_format;
+ mf_media_type_to_wg_format(converter->input_type, &input_format);
+
+ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format, NULL)))
+ converter->stream = wg_parser_get_stream(converter->parser, 0);
+ }
+
+ LeaveCriticalSection(&converter->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI audio_converter_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface);
+ IMFMediaType *ret;
+ HRESULT hr;
+
+ TRACE("%p, %u, %p.\n", converter, id, type);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (FAILED(hr = MFCreateMediaType(&ret)))
+ return hr;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (converter->input_type)
+ hr = IMFMediaType_CopyAllItems(converter->input_type, (IMFAttributes *)ret);
+ else
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ LeaveCriticalSection(&converter->cs);
+
+ if (SUCCEEDED(hr))
+ *type = ret;
+ else
+ IMFMediaType_Release(ret);
+
+ return hr;
+}
+
+static HRESULT WINAPI audio_converter_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface);
+ IMFMediaType *ret;
+ HRESULT hr;
+
+ TRACE("%p, %u, %p.\n", converter, id, type);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (FAILED(hr = MFCreateMediaType(&ret)))
+ return hr;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (converter->output_type)
+ hr = IMFMediaType_CopyAllItems(converter->output_type, (IMFAttributes *)ret);
+ else
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ LeaveCriticalSection(&converter->cs);
+
+ if (SUCCEEDED(hr))
+ *type = ret;
+ else
+ IMFMediaType_Release(ret);
+
+ return hr;
+}
+
+static HRESULT WINAPI audio_converter_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
+{
+ FIXME("%p, %u, %p.\n", iface, id, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI audio_converter_GetOutputStatus(IMFTransform *iface, DWORD *flags)
+{
+ FIXME("%p, %p.\n", iface, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI audio_converter_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
+{
+ FIXME("%p, %s, %s.\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper));
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI audio_converter_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
+{
+ TRACE("%p, %u, %p.\n", iface, id, event);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
+{
+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface);
+ struct wg_parser_buffer wg_buffer;
+
+ TRACE("%p, %u %lu.\n", iface, message, param);
+
+ switch(message)
+ {
+ case MFT_MESSAGE_COMMAND_FLUSH:
+ {
+ EnterCriticalSection(&converter->cs);
+ if (!converter->buffer_inflight)
+ {
+ LeaveCriticalSection(&converter->cs);
+ return S_OK;
+ }
+
+ wg_parser_stream_get_buffer(converter->stream, &wg_buffer);
+ wg_parser_stream_release_buffer(converter->stream);
+ converter->buffer_inflight = FALSE;
+
+ LeaveCriticalSection(&converter->cs);
+ return S_OK;
+ }
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ return S_OK;
+ default:
+ FIXME("Unhandled message type %x.\n", message);
+ return E_NOTIMPL;
+ }
+}
+
+static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
+{
+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface);
+ IMFMediaBuffer *buffer = NULL;
+ unsigned char *buffer_data;
+ DWORD buffer_size;
+ uint64_t offset;
+ uint32_t size;
+ HRESULT hr;
+
+ TRACE("%p, %u, %p, %#x.\n", iface, id, sample, flags);
+
+ if (flags)
+ WARN("Unsupported flags %#x.\n", flags);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (!converter->stream)
+ {
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+ goto done;
+ }
+
+ if (converter->buffer_inflight)
+ {
+ hr = MF_E_NOTACCEPTING;
+ goto done;
+ }
+
+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer)))
+ goto done;
+
+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, &buffer_size)))
+ goto done;
+
+ if (!wg_parser_get_next_read_offset(converter->parser, &offset, &size))
+ {
+ hr = MF_E_UNEXPECTED;
+ IMFMediaBuffer_Unlock(buffer);
+ goto done;
+ }
+
+ wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, buffer_size);
+
+ IMFMediaBuffer_Unlock(buffer);
+ converter->buffer_inflight = TRUE;
+ if (FAILED(IMFSample_GetSampleTime(sample, &converter->buffer_pts)))
+ converter->buffer_pts = -1;
+ if (FAILED(IMFSample_GetSampleDuration(sample, &converter->buffer_dur)))
+ converter->buffer_dur = -1;
+
+done:
+ if (buffer)
+ IMFMediaBuffer_Release(buffer);
+ LeaveCriticalSection(&converter->cs);
+ return hr;
+}
+
+static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
+{
+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface);
+ IMFSample *allocated_sample = NULL;
+ struct wg_parser_buffer wg_buffer;
+ IMFMediaBuffer *buffer = NULL;
+ unsigned char *buffer_data;
+ DWORD buffer_len;
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status);
+
+ if (flags)
+ WARN("Unsupported flags %#x.\n", flags);
+
+ if (!count)
+ return S_OK;
+
+ if (count != 1)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (samples[0].dwStreamID != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (!converter->stream)
+ {
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+ goto done;
+ }
+
+ if (!converter->buffer_inflight)
+ {
+ hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
+ goto done;
+ }
+
+ if (!wg_parser_stream_get_buffer(converter->stream, &wg_buffer))
+ assert(0);
+
+ if (!samples[0].pSample)
+ {
+ if (FAILED(hr = MFCreateMemoryBuffer(wg_buffer.size, &buffer)))
+ {
+ ERR("Failed to create buffer, hr %#x.\n", hr);
+ goto done;
+ }
+
+ if (FAILED(hr = MFCreateSample(&allocated_sample)))
+ {
+ ERR("Failed to create sample, hr %#x.\n", hr);
+ goto done;
+ }
+
+ samples[0].pSample = allocated_sample;
+
+ if (FAILED(hr = IMFSample_AddBuffer(samples[0].pSample, buffer)))
+ {
+ ERR("Failed to add buffer, hr %#x.\n", hr);
+ goto done;
+ }
+
+ IMFMediaBuffer_Release(buffer);
+ buffer = NULL;
+ }
+
+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer)))
+ {
+ ERR("Failed to get buffer from sample, hr %#x.\n", hr);
+ goto done;
+ }
+
+ if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len)))
+ {
+ ERR("Failed to get buffer size, hr %#x.\n", hr);
+ goto done;
+ }
+
+ if (buffer_len < wg_buffer.size)
+ {
+ WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n",
+ buffer_len, wg_buffer.size);
+
+ hr = MF_E_BUFFERTOOSMALL;
+ goto done;
+ }
+
+ if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, wg_buffer.size)))
+ {
+ ERR("Failed to set size, hr %#x.\n", hr);
+ goto done;
+ }
+
+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL)))
+ {
+ ERR("Failed to lock buffer hr %#x.\n", hr);
+ goto done;
+ }
+
+ if (!wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, wg_buffer.size))
+ {
+ ERR("Failed to copy buffer.\n");
+ IMFMediaBuffer_Unlock(buffer);
+ hr = E_FAIL;
+ goto done;
+ }
+
+ IMFMediaBuffer_Unlock(buffer);
+
+ wg_parser_stream_release_buffer(converter->stream);
+ converter->buffer_inflight = FALSE;
+
+ if (converter->buffer_pts != -1)
+ IMFSample_SetSampleTime(samples[0].pSample, converter->buffer_pts);
+ if (converter->buffer_dur != -1)
+ IMFSample_SetSampleDuration(samples[0].pSample, converter->buffer_dur);
+
+ samples[0].dwStatus = 0;
+ samples[0].pEvents = NULL;
+
+ done:
+ if (buffer)
+ IMFMediaBuffer_Release(buffer);
+ if (allocated_sample && FAILED(hr))
+ {
+ IMFSample_Release(allocated_sample);
+ samples[0].pSample = NULL;
+ }
+ LeaveCriticalSection(&converter->cs);
+ return hr;
+}
+
+static const IMFTransformVtbl audio_converter_vtbl =
+{
+ audio_converter_QueryInterface,
+ audio_converter_AddRef,
+ audio_converter_Release,
+ audio_converter_GetStreamLimits,
+ audio_converter_GetStreamCount,
+ audio_converter_GetStreamIDs,
+ audio_converter_GetInputStreamInfo,
+ audio_converter_GetOutputStreamInfo,
+ audio_converter_GetAttributes,
+ audio_converter_GetInputStreamAttributes,
+ audio_converter_GetOutputStreamAttributes,
+ audio_converter_DeleteInputStream,
+ audio_converter_AddInputStreams,
+ audio_converter_GetInputAvailableType,
+ audio_converter_GetOutputAvailableType,
+ audio_converter_SetInputType,
+ audio_converter_SetOutputType,
+ audio_converter_GetInputCurrentType,
+ audio_converter_GetOutputCurrentType,
+ audio_converter_GetInputStatus,
+ audio_converter_GetOutputStatus,
+ audio_converter_SetOutputBounds,
+ audio_converter_ProcessEvent,
+ audio_converter_ProcessMessage,
+ audio_converter_ProcessInput,
+ audio_converter_ProcessOutput,
+};
+
+HRESULT audio_converter_create(REFIID riid, void **ret)
+{
+ struct audio_converter *object;
+ HRESULT hr;
+
+ TRACE("%s %p\n", debugstr_guid(riid), ret);
+
+ if (!(object = calloc(1, sizeof(*object))))
+ return E_OUTOFMEMORY;
+
+ object->IMFTransform_iface.lpVtbl = &audio_converter_vtbl;
+ object->refcount = 1;
+
+ InitializeCriticalSection(&object->cs);
+ object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": audio_converter_lock");
+
+ if (FAILED(hr = MFCreateAttributes(&object->attributes, 0)))
+ {
+ IMFTransform_Release(&object->IMFTransform_iface);
+ return hr;
+ }
+
+ if (FAILED(hr = MFCreateAttributes(&object->output_attributes, 0)))
+ {
+ IMFTransform_Release(&object->IMFTransform_iface);
+ return hr;
+ }
+
+ if (!(object->parser = wg_parser_create(WG_PARSER_AUDIOCONV, true)))
+ {
+ ERR("Failed to create audio converter due to GStreamer error.\n");
+ IMFTransform_Release(&object->IMFTransform_iface);
+ return E_OUTOFMEMORY;
+ }
+
+ *ret = &object->IMFTransform_iface;
+ return S_OK;
+}
diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c
index eada3df18ad..9081dc39eab 100644
--- wine/dlls/mfplat/buffer.c
+++ wine/dlls/mfplat/buffer.c
@@ -18,8 +18,6 @@
#define COBJMACROS
-#include <malloc.h>
-
#include "mfplat_private.h"
#include "rtworkq.h"
@@ -28,6 +26,8 @@
#include "d3d9.h"
#include "evr.h"
+#include "wine/debug.h"
+
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
#define ALIGN_SIZE(size, alignment) (((size) + (alignment)) & ~((alignment)))
@@ -49,7 +49,7 @@ struct buffer
struct
{
BYTE *linear_buffer;
- DWORD plane_size;
+ unsigned int plane_size;
BYTE *scanline0;
unsigned int width;
@@ -148,7 +148,7 @@ static ULONG WINAPI memory_buffer_AddRef(IMFMediaBuffer *iface)
struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
ULONG refcount = InterlockedIncrement(&buffer->refcount);
- TRACE("%p, refcount %lu.\n", buffer, refcount);
+ TRACE("%p, refcount %u.\n", buffer, refcount);
return refcount;
}
@@ -158,7 +158,7 @@ static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface)
struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
ULONG refcount = InterlockedDecrement(&buffer->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
{
@@ -173,7 +173,7 @@ static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface)
}
DeleteCriticalSection(&buffer->cs);
free(buffer->_2d.linear_buffer);
- _aligned_free(buffer->data);
+ free(buffer->data);
free(buffer);
}
@@ -223,7 +223,7 @@ static HRESULT WINAPI memory_buffer_SetCurrentLength(IMFMediaBuffer *iface, DWOR
{
struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
- TRACE("%p, %lu.\n", iface, current_length);
+ TRACE("%p, %u.\n", iface, current_length);
if (current_length > buffer->max_length)
return E_INVALIDARG;
@@ -309,12 +309,8 @@ static HRESULT WINAPI memory_1d_2d_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat
hr = MF_E_INVALIDREQUEST;
else if (!buffer->_2d.linear_buffer)
{
- if (!(buffer->_2d.linear_buffer = malloc(buffer->_2d.plane_size)))
+ if (!(buffer->_2d.linear_buffer = malloc(ALIGN_SIZE(buffer->_2d.plane_size, MF_64_BYTE_ALIGNMENT))))
hr = E_OUTOFMEMORY;
-
- if (SUCCEEDED(hr))
- copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->data, buffer->_2d.pitch,
- buffer->_2d.width, buffer->_2d.height);
}
if (SUCCEEDED(hr))
@@ -384,7 +380,7 @@ static HRESULT WINAPI d3d9_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat
{
D3DLOCKED_RECT rect;
- if (!(buffer->_2d.linear_buffer = malloc(buffer->_2d.plane_size)))
+ if (!(buffer->_2d.linear_buffer = malloc(ALIGN_SIZE(buffer->_2d.plane_size, MF_64_BYTE_ALIGNMENT))))
hr = E_OUTOFMEMORY;
if (SUCCEEDED(hr))
@@ -449,7 +445,7 @@ static HRESULT WINAPI d3d9_surface_buffer_SetCurrentLength(IMFMediaBuffer *iface
{
struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
- TRACE("%p, %lu.\n", iface, current_length);
+ TRACE("%p, %u.\n", iface, current_length);
buffer->current_length = current_length;
@@ -601,14 +597,14 @@ static HRESULT WINAPI memory_2d_buffer_GetContiguousLength(IMF2DBuffer2 *iface,
static HRESULT WINAPI memory_2d_buffer_ContiguousCopyTo(IMF2DBuffer2 *iface, BYTE *dest_buffer, DWORD dest_length)
{
- FIXME("%p, %p, %lu.\n", iface, dest_buffer, dest_length);
+ FIXME("%p, %p, %u.\n", iface, dest_buffer, dest_length);
return E_NOTIMPL;
}
static HRESULT WINAPI memory_2d_buffer_ContiguousCopyFrom(IMF2DBuffer2 *iface, const BYTE *src_buffer, DWORD src_length)
{
- FIXME("%p, %p, %lu.\n", iface, src_buffer, src_length);
+ FIXME("%p, %p, %u.\n", iface, src_buffer, src_length);
return E_NOTIMPL;
}
@@ -670,14 +666,13 @@ static HRESULT WINAPI d3d9_surface_buffer_Lock2D(IMF2DBuffer2 *iface, BYTE **sca
if (buffer->_2d.linear_buffer)
hr = MF_E_UNEXPECTED;
- else if (!buffer->_2d.locks)
+ else if (!buffer->_2d.locks++)
{
hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &buffer->d3d9_surface.rect, NULL, 0);
}
if (SUCCEEDED(hr))
{
- buffer->_2d.locks++;
*scanline0 = buffer->d3d9_surface.rect.pBits;
*pitch = buffer->d3d9_surface.rect.Pitch;
}
@@ -756,14 +751,13 @@ static HRESULT WINAPI d3d9_surface_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBu
if (buffer->_2d.linear_buffer)
hr = MF_E_UNEXPECTED;
- else if (!buffer->_2d.locks)
+ else if (!buffer->_2d.locks++)
{
hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &buffer->d3d9_surface.rect, NULL, 0);
}
if (SUCCEEDED(hr))
{
- buffer->_2d.locks++;
*scanline0 = buffer->d3d9_surface.rect.pBits;
*pitch = buffer->d3d9_surface.rect.Pitch;
if (buffer_start)
@@ -897,7 +891,7 @@ static HRESULT dxgi_surface_buffer_create_readback_texture(struct buffer *buffer
texture_desc.MiscFlags = 0;
texture_desc.MipLevels = 1;
if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &buffer->dxgi_surface.rb_texture)))
- WARN("Failed to create readback texture, hr %#lx.\n", hr);
+ WARN("Failed to create readback texture, hr %#x.\n", hr);
ID3D11Device_Release(device);
@@ -922,7 +916,7 @@ static HRESULT dxgi_surface_buffer_map(struct buffer *buffer)
if (FAILED(hr = ID3D11DeviceContext_Map(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture,
0, D3D11_MAP_READ_WRITE, 0, &buffer->dxgi_surface.map_desc)))
{
- WARN("Failed to map readback texture, hr %#lx.\n", hr);
+ WARN("Failed to map readback texture, hr %#x.\n", hr);
}
ID3D11DeviceContext_Release(immediate_context);
@@ -965,7 +959,7 @@ static HRESULT WINAPI dxgi_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat
hr = MF_E_INVALIDREQUEST;
else if (!buffer->_2d.linear_buffer)
{
- if (!(buffer->_2d.linear_buffer = malloc(buffer->_2d.plane_size)))
+ if (!(buffer->_2d.linear_buffer = malloc(ALIGN_SIZE(buffer->_2d.plane_size, MF_64_BYTE_ALIGNMENT))))
hr = E_OUTOFMEMORY;
if (SUCCEEDED(hr))
@@ -1024,7 +1018,7 @@ static HRESULT WINAPI dxgi_surface_buffer_SetCurrentLength(IMFMediaBuffer *iface
{
struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
- TRACE("%p, %lu.\n", iface, current_length);
+ TRACE("%p, %u.\n", iface, current_length);
buffer->current_length = current_length;
@@ -1262,24 +1256,8 @@ static const IMFDXGIBufferVtbl dxgi_buffer_vtbl =
static HRESULT memory_buffer_init(struct buffer *buffer, DWORD max_length, DWORD alignment,
const IMFMediaBufferVtbl *vtbl)
{
- if (alignment < MF_16_BYTE_ALIGNMENT)
- alignment = MF_16_BYTE_ALIGNMENT;
- alignment++;
-
- if (alignment & (alignment - 1))
- {
- alignment--;
- alignment |= alignment >> 1;
- alignment |= alignment >> 2;
- alignment |= alignment >> 4;
- alignment |= alignment >> 8;
- alignment |= alignment >> 16;
- alignment++;
- }
-
- if (!(buffer->data = _aligned_malloc(max_length, alignment)))
+ if (!(buffer->data = calloc(1, ALIGN_SIZE(max_length, alignment))))
return E_OUTOFMEMORY;
- memset(buffer->data, 0, max_length);
buffer->IMFMediaBuffer_iface.lpVtbl = vtbl;
buffer->refcount = 1;
@@ -1328,10 +1306,9 @@ static p_copy_image_func get_2d_buffer_copy_func(DWORD fourcc)
static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, IMFMediaBuffer **buffer)
{
- unsigned int stride, max_length;
- unsigned int row_alignment;
+ unsigned int stride, max_length, plane_size;
struct buffer *object;
- DWORD plane_size;
+ unsigned int row_alignment;
GUID subtype;
BOOL is_yuv;
HRESULT hr;
@@ -1389,7 +1366,7 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bo
max_length = pitch * height;
}
- if (FAILED(hr = memory_buffer_init(object, max_length, row_alignment, &memory_1d_2d_buffer_vtbl)))
+ if (FAILED(hr = memory_buffer_init(object, max_length, MF_1_BYTE_ALIGNMENT, &memory_1d_2d_buffer_vtbl)))
{
free(object);
return hr;
@@ -1462,7 +1439,7 @@ static HRESULT create_dxgi_surface_buffer(IUnknown *surface, unsigned int sub_re
if (FAILED(hr = IUnknown_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture)))
{
- WARN("Failed to get texture interface, hr %#lx.\n", hr);
+ WARN("Failed to get texture interface, hr %#x.\n", hr);
return hr;
}
@@ -1514,7 +1491,7 @@ static HRESULT create_dxgi_surface_buffer(IUnknown *surface, unsigned int sub_re
*/
HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer)
{
- TRACE("%lu, %p.\n", max_length, buffer);
+ TRACE("%u, %p.\n", max_length, buffer);
return create_1d_buffer(max_length, MF_1_BYTE_ALIGNMENT, buffer);
}
@@ -1524,7 +1501,7 @@ HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer)
*/
HRESULT WINAPI MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IMFMediaBuffer **buffer)
{
- TRACE("%lu, %lu, %p.\n", max_length, alignment, buffer);
+ TRACE("%u, %u, %p.\n", max_length, alignment, buffer);
return create_1d_buffer(max_length, alignment, buffer);
}
@@ -1534,7 +1511,7 @@ HRESULT WINAPI MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IM
*/
HRESULT WINAPI MFCreate2DMediaBuffer(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, IMFMediaBuffer **buffer)
{
- TRACE("%lu, %lu, %s, %d, %p.\n", width, height, debugstr_fourcc(fourcc), bottom_up, buffer);
+ TRACE("%u, %u, %s, %d, %p.\n", width, height, debugstr_fourcc(fourcc), bottom_up, buffer);
return create_2d_buffer(width, height, fourcc, bottom_up, buffer);
}
@@ -1582,7 +1559,7 @@ HRESULT WINAPI MFCreateMediaBufferFromMediaType(IMFMediaType *media_type, LONGLO
HRESULT hr;
GUID major;
- TRACE("%p, %s, %lu, %lu, %p.\n", media_type, debugstr_time(duration), min_length, alignment, buffer);
+ TRACE("%p, %s, %u, %u, %p.\n", media_type, debugstr_time(duration), min_length, alignment, buffer);
if (!media_type)
return E_INVALIDARG;
@@ -1596,8 +1573,6 @@ HRESULT WINAPI MFCreateMediaBufferFromMediaType(IMFMediaType *media_type, LONGLO
if (FAILED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment)))
WARN("Block alignment was not specified.\n");
- alignment = max(16, alignment);
-
if (block_alignment)
{
avg_length = 0;
@@ -1612,6 +1587,8 @@ HRESULT WINAPI MFCreateMediaBufferFromMediaType(IMFMediaType *media_type, LONGLO
}
}
+ alignment = max(16, alignment);
+
length = buffer_get_aligned_length(avg_length + 1, alignment);
length = buffer_get_aligned_length(length, block_alignment);
}
@@ -1620,7 +1597,7 @@ HRESULT WINAPI MFCreateMediaBufferFromMediaType(IMFMediaType *media_type, LONGLO
length = max(length, min_length);
- return create_1d_buffer(length, alignment - 1, buffer);
+ return create_1d_buffer(length, MF_1_BYTE_ALIGNMENT, buffer);
}
else
FIXME("Major type %s is not supported.\n", debugstr_guid(&major));
diff --git a/dlls/mfplat/colorconvert.c b/dlls/mfplat/colorconvert.c
new file mode 100644
index 00000000000..92322e877ec
--- /dev/null
+++ wine/dlls/mfplat/colorconvert.c
@@ -0,0 +1,901 @@
+/* GStreamer Color Converter
+ *
+ * Copyright 2020 Derek Lesho
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "gst_private.h"
+
+#include "mfapi.h"
+#include "mferror.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+static const GUID *raw_types[] = {
+ &MFVideoFormat_RGB24,
+ &MFVideoFormat_RGB32,
+ &MFVideoFormat_RGB555,
+ &MFVideoFormat_RGB8,
+ &MFVideoFormat_AYUV,
+ &MFVideoFormat_I420,
+ &MFVideoFormat_IYUV,
+ &MFVideoFormat_NV11,
+ &MFVideoFormat_NV12,
+ &MFVideoFormat_UYVY,
+ &MFVideoFormat_v216,
+ &MFVideoFormat_v410,
+ &MFVideoFormat_YUY2,
+ &MFVideoFormat_YVYU,
+ &MFVideoFormat_YVYU,
+};
+
+struct color_converter
+{
+ IMFTransform IMFTransform_iface;
+ LONG refcount;
+ IMFMediaType *input_type;
+ IMFMediaType *output_type;
+ CRITICAL_SECTION cs;
+ BOOL buffer_inflight;
+ LONGLONG buffer_pts, buffer_dur;
+ struct wg_parser *parser;
+ struct wg_parser_stream *stream;
+};
+
+static struct color_converter *impl_color_converter_from_IMFTransform(IMFTransform *iface)
+{
+ return CONTAINING_RECORD(iface, struct color_converter, IMFTransform_iface);
+}
+
+static HRESULT WINAPI color_converter_QueryInterface(IMFTransform *iface, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualGUID(riid, &IID_IMFTransform) ||
+ IsEqualGUID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IMFTransform_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI color_converter_AddRef(IMFTransform *iface)
+{
+ struct color_converter *transform = impl_color_converter_from_IMFTransform(iface);
+ ULONG refcount = InterlockedIncrement(&transform->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI color_converter_Release(IMFTransform *iface)
+{
+ struct color_converter *transform = impl_color_converter_from_IMFTransform(iface);
+ ULONG refcount = InterlockedDecrement(&transform->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ transform->cs.DebugInfo->Spare[0] = 0;
+ DeleteCriticalSection(&transform->cs);
+ if (transform->output_type)
+ IMFMediaType_Release(transform->output_type);
+ if (transform->stream)
+ wg_parser_disconnect(transform->parser);
+ if (transform->parser)
+ wg_parser_destroy(transform->parser);
+ free(transform);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI color_converter_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum,
+ DWORD *output_minimum, DWORD *output_maximum)
+{
+ TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum);
+
+ *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI color_converter_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
+{
+ TRACE("%p, %p, %p.\n", iface, inputs, outputs);
+
+ *inputs = *outputs = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI color_converter_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
+ DWORD output_size, DWORD *outputs)
+{
+ TRACE("%p %u %p %u %p.\n", iface, input_size, inputs, output_size, outputs);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ UINT64 framesize;
+ GUID subtype;
+
+ TRACE("%p %u %p.\n", iface, id, info);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE;
+ info->cbMaxLookahead = 0;
+ info->cbAlignment = 0;
+ info->hnsMaxLatency = 0;
+ info->cbSize = 0;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (converter->input_type)
+ {
+ if (SUCCEEDED(IMFMediaType_GetGUID(converter->input_type, &MF_MT_SUBTYPE, &subtype)) &&
+ SUCCEEDED(IMFMediaType_GetUINT64(converter->input_type, &MF_MT_FRAME_SIZE, &framesize)))
+ {
+ MFCalculateImageSize(&subtype, framesize >> 32, (UINT32) framesize, &info->cbSize);
+ }
+
+ if (!info->cbSize)
+ WARN("Failed to get desired input buffer size, the non-provided sample path will likely break\n");
+ }
+
+ LeaveCriticalSection(&converter->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI color_converter_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ UINT64 framesize;
+ GUID subtype;
+
+ TRACE("%p %u %p.\n", iface, id, info);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ info->dwFlags = MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES | MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER;
+ info->cbAlignment = 0;
+ info->cbSize = 0;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (converter->output_type)
+ {
+ if (SUCCEEDED(IMFMediaType_GetGUID(converter->output_type, &MF_MT_SUBTYPE, &subtype)) &&
+ SUCCEEDED(IMFMediaType_GetUINT64(converter->output_type, &MF_MT_FRAME_SIZE, &framesize)))
+ {
+ MFCalculateImageSize(&subtype, framesize >> 32, (UINT32) framesize, &info->cbSize);
+ }
+
+ if (!info->cbSize)
+ WARN("Failed to get desired output buffer size, the non-provided sample path will likely break\n");
+ }
+
+ LeaveCriticalSection(&converter->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI color_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
+{
+ FIXME("%p, %p.\n", iface, attributes);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_GetInputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ FIXME("%p, %u, %p.\n", iface, id, attributes);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_GetOutputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ FIXME("%p, %u, %p.\n", iface, id, attributes);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_DeleteInputStream(IMFTransform *iface, DWORD id)
+{
+ TRACE("%p, %u.\n", iface, id);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
+{
+ TRACE("%p, %u, %p.\n", iface, streams, ids);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ IMFMediaType *ret;
+ HRESULT hr;
+
+ TRACE("%p, %u, %u, %p.\n", iface, id, index, type);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (index >= ARRAY_SIZE(raw_types))
+ return MF_E_NO_MORE_TYPES;
+
+ if (FAILED(hr = MFCreateMediaType(&ret)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaType_SetGUID(ret, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
+ {
+ IMFMediaType_Release(ret);
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_SetGUID(ret, &MF_MT_SUBTYPE, raw_types[index])))
+ {
+ IMFMediaType_Release(ret);
+ return hr;
+ }
+
+ *type = ret;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ IMFMediaType *ret;
+ HRESULT hr;
+
+ TRACE("%p, %u, %u, %p.\n", iface, id, index, type);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (index >= ARRAY_SIZE(raw_types))
+ return MF_E_NO_MORE_TYPES;
+
+ if (FAILED(hr = MFCreateMediaType(&ret)))
+ return hr;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (converter->input_type)
+ IMFMediaType_CopyAllItems(converter->input_type, (IMFAttributes *) ret);
+
+ LeaveCriticalSection(&converter->cs);
+
+ if (FAILED(hr = IMFMediaType_SetGUID(ret, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
+ {
+ IMFMediaType_Release(ret);
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_SetGUID(ret, &MF_MT_SUBTYPE, raw_types[index])))
+ {
+ IMFMediaType_Release(ret);
+ return hr;
+ }
+
+ *type = ret;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ UINT64 input_framesize, output_framesize;
+ GUID major_type, subtype;
+ struct wg_format format;
+ unsigned int i;
+ HRESULT hr;
+
+ TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (!type)
+ {
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ return S_OK;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (converter->input_type)
+ {
+ if (converter->stream)
+ {
+ wg_parser_disconnect(converter->parser);
+ converter->stream = NULL;
+ }
+ IMFMediaType_Release(converter->input_type);
+ converter->input_type = NULL;
+ }
+
+ LeaveCriticalSection(&converter->cs);
+
+ return S_OK;
+ }
+
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type)))
+ return MF_E_INVALIDTYPE;
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ return MF_E_INVALIDTYPE;
+
+ if (!IsEqualGUID(&major_type, &MFMediaType_Video))
+ return MF_E_INVALIDTYPE;
+
+ for (i = 0; i < ARRAY_SIZE(raw_types); i++)
+ {
+ if (IsEqualGUID(&subtype, raw_types[i]))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(raw_types))
+ return MF_E_INVALIDTYPE;
+
+ EnterCriticalSection(&converter->cs);
+
+ if(converter->output_type
+ && SUCCEEDED(IMFMediaType_GetUINT64(converter->output_type, &MF_MT_FRAME_SIZE, &output_framesize))
+ && SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &input_framesize))
+ && input_framesize != output_framesize)
+ {
+ LeaveCriticalSection(&converter->cs);
+ return MF_E_INVALIDTYPE;
+ }
+
+ LeaveCriticalSection(&converter->cs);
+
+ mf_media_type_to_wg_format(type, &format);
+ if (!format.major_type)
+ return MF_E_INVALIDTYPE;
+
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ return S_OK;
+
+ EnterCriticalSection(&converter->cs);
+
+ hr = S_OK;
+
+ if (!converter->input_type)
+ hr = MFCreateMediaType(&converter->input_type);
+
+ if (SUCCEEDED(hr))
+ hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->input_type);
+
+ if (FAILED(hr))
+ {
+ IMFMediaType_Release(converter->input_type);
+ converter->input_type = NULL;
+ }
+
+ if (converter->stream)
+ {
+ wg_parser_disconnect(converter->parser);
+ converter->stream = NULL;
+ }
+
+ if (converter->input_type && converter->output_type)
+ {
+ struct wg_format output_format;
+ mf_media_type_to_wg_format(converter->output_type, &output_format);
+
+ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format, NULL)))
+ converter->stream = wg_parser_get_stream(converter->parser, 0);
+ }
+
+ LeaveCriticalSection(&converter->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ UINT64 input_framesize, output_framesize;
+ GUID major_type, subtype;
+ struct wg_format format;
+ unsigned int i;
+ HRESULT hr;
+
+ TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (!type)
+ {
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ return S_OK;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (converter->output_type)
+ {
+ if (converter->stream)
+ {
+ wg_parser_disconnect(converter->parser);
+ converter->stream = NULL;
+ }
+ IMFMediaType_Release(converter->output_type);
+ converter->output_type = NULL;
+ }
+
+ LeaveCriticalSection(&converter->cs);
+
+ return S_OK;
+ }
+
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type)))
+ return MF_E_INVALIDTYPE;
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ return MF_E_INVALIDTYPE;
+
+ if (!IsEqualGUID(&major_type, &MFMediaType_Video))
+ return MF_E_INVALIDTYPE;
+
+ for (i = 0; i < ARRAY_SIZE(raw_types); i++)
+ {
+ if (IsEqualGUID(&subtype, raw_types[i]))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(raw_types))
+ return MF_E_INVALIDTYPE;
+
+ EnterCriticalSection(&converter->cs);
+
+ if(converter->input_type
+ && SUCCEEDED(IMFMediaType_GetUINT64(converter->input_type, &MF_MT_FRAME_SIZE, &input_framesize))
+ && SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &output_framesize))
+ && input_framesize != output_framesize)
+ {
+ LeaveCriticalSection(&converter->cs);
+ return MF_E_INVALIDTYPE;
+ }
+
+ LeaveCriticalSection(&converter->cs);
+
+ mf_media_type_to_wg_format(type, &format);
+ if (!format.major_type)
+ return MF_E_INVALIDTYPE;
+
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ return S_OK;
+
+ EnterCriticalSection(&converter->cs);
+
+ hr = S_OK;
+
+ if (!converter->output_type)
+ hr = MFCreateMediaType(&converter->output_type);
+
+ if (SUCCEEDED(hr))
+ hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->output_type);
+
+ if (FAILED(hr))
+ {
+ IMFMediaType_Release(converter->output_type);
+ converter->output_type = NULL;
+ }
+
+ if (converter->stream)
+ {
+ wg_parser_disconnect(converter->parser);
+ converter->stream = NULL;
+ }
+
+ if (converter->input_type && converter->output_type)
+ {
+ struct wg_format input_format;
+ mf_media_type_to_wg_format(converter->input_type, &input_format);
+
+ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format, NULL)))
+ converter->stream = wg_parser_get_stream(converter->parser, 0);
+ }
+
+ LeaveCriticalSection(&converter->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ FIXME("%p, %u, %p.\n", iface, id, type);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ IMFMediaType *ret;
+ HRESULT hr;
+
+ TRACE("%p, %u, %p.\n", converter, id, type);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (FAILED(hr = MFCreateMediaType(&ret)))
+ return hr;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (converter->output_type)
+ hr = IMFMediaType_CopyAllItems(converter->output_type, (IMFAttributes *)ret);
+ else
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ LeaveCriticalSection(&converter->cs);
+
+ if (SUCCEEDED(hr))
+ *type = ret;
+ else
+ IMFMediaType_Release(ret);
+
+ return hr;
+}
+
+static HRESULT WINAPI color_converter_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
+{
+ FIXME("%p, %u, %p.\n", iface, id, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_GetOutputStatus(IMFTransform *iface, DWORD *flags)
+{
+ FIXME("%p, %p.\n", iface, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
+{
+ FIXME("%p, %s, %s.\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper));
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
+{
+ TRACE("%p, %u, %p.\n", iface, id, event);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ struct wg_parser_buffer wg_buffer;
+
+ TRACE("%p, %u %lu.\n", iface, message, param);
+
+ switch(message)
+ {
+ case MFT_MESSAGE_COMMAND_FLUSH:
+ {
+ EnterCriticalSection(&converter->cs);
+ if (!converter->buffer_inflight)
+ {
+ LeaveCriticalSection(&converter->cs);
+ return S_OK;
+ }
+
+ wg_parser_stream_get_buffer(converter->stream, &wg_buffer);
+ wg_parser_stream_release_buffer(converter->stream);
+ converter->buffer_inflight = FALSE;
+
+ LeaveCriticalSection(&converter->cs);
+ return S_OK;
+ }
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ return S_OK;
+ default:
+ FIXME("Unhandled message type %x.\n", message);
+ return E_NOTIMPL;
+ }
+}
+
+static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ IMFMediaBuffer *buffer = NULL;
+ unsigned char *buffer_data;
+ DWORD buffer_size;
+ uint64_t offset;
+ uint32_t size;
+ HRESULT hr;
+
+ TRACE("%p, %u, %p, %#x.\n", iface, id, sample, flags);
+
+ if (flags)
+ WARN("Unsupported flags %#x.\n", flags);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (!converter->stream)
+ {
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+ goto done;
+ }
+
+ if (converter->buffer_inflight)
+ {
+ hr = MF_E_NOTACCEPTING;
+ goto done;
+ }
+
+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer)))
+ goto done;
+
+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, &buffer_size)))
+ goto done;
+
+ for (;;)
+ {
+ if (!wg_parser_get_next_read_offset(converter->parser, &offset, &size))
+ {
+ TRACE("sink unconnected\n");
+ continue;
+ }
+
+ wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size));
+
+ if (buffer_size <= size)
+ break;
+
+ buffer_data += size;
+ buffer_size -= size;
+ }
+
+ IMFMediaBuffer_Unlock(buffer);
+ converter->buffer_inflight = TRUE;
+ if (FAILED(IMFSample_GetSampleTime(sample, &converter->buffer_pts)))
+ converter->buffer_pts = -1;
+ if (FAILED(IMFSample_GetSampleDuration(sample, &converter->buffer_dur)))
+ converter->buffer_dur = -1;
+
+done:
+ if (buffer)
+ IMFMediaBuffer_Release(buffer);
+ LeaveCriticalSection(&converter->cs);
+ return hr;
+}
+
+static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ IMFSample *allocated_sample = NULL;
+ struct wg_parser_buffer wg_buffer;
+ IMFMediaBuffer *buffer = NULL;
+ unsigned char *buffer_data;
+ DWORD buffer_len;
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status);
+
+ if (flags)
+ WARN("Unsupported flags %#x.\n", flags);
+
+ if (!count)
+ return S_OK;
+
+ if (count != 1)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (samples[0].dwStreamID != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (!converter->stream)
+ {
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+ goto done;
+ }
+
+ if (!converter->buffer_inflight)
+ {
+ hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
+ goto done;
+ }
+
+ if (!wg_parser_stream_get_buffer(converter->stream, &wg_buffer))
+ assert(0);
+
+ if (!samples[0].pSample)
+ {
+ if (FAILED(hr = MFCreateMemoryBuffer(wg_buffer.size, &buffer)))
+ {
+ ERR("Failed to create buffer, hr %#x.\n", hr);
+ goto done;
+ }
+
+ if (FAILED(hr = MFCreateSample(&allocated_sample)))
+ {
+ ERR("Failed to create sample, hr %#x.\n", hr);
+ goto done;
+ }
+
+ samples[0].pSample = allocated_sample;
+
+ if (FAILED(hr = IMFSample_AddBuffer(samples[0].pSample, buffer)))
+ {
+ ERR("Failed to add buffer, hr %#x.\n", hr);
+ goto done;
+ }
+
+ IMFMediaBuffer_Release(buffer);
+ buffer = NULL;
+ }
+
+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer)))
+ {
+ ERR("Failed to get buffer from sample, hr %#x.\n", hr);
+ goto done;
+ }
+
+ if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len)))
+ {
+ ERR("Failed to get buffer size, hr %#x.\n", hr);
+ goto done;
+ }
+
+ if (buffer_len < wg_buffer.size)
+ {
+ WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n",
+ buffer_len, wg_buffer.size);
+
+ hr = MF_E_BUFFERTOOSMALL;
+ goto done;
+ }
+
+ if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, wg_buffer.size)))
+ {
+ ERR("Failed to set size, hr %#x.\n", hr);
+ goto done;
+ }
+
+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL)))
+ {
+ ERR("Failed to lock buffer hr %#x.\n", hr);
+ goto done;
+ }
+
+ if (!wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, wg_buffer.size))
+ {
+ ERR("Failed to copy buffer.\n");
+ IMFMediaBuffer_Unlock(buffer);
+ hr = E_FAIL;
+ goto done;
+ }
+
+ IMFMediaBuffer_Unlock(buffer);
+
+ wg_parser_stream_release_buffer(converter->stream);
+ converter->buffer_inflight = FALSE;
+
+ if (converter->buffer_pts != -1)
+ IMFSample_SetSampleTime(samples[0].pSample, converter->buffer_pts);
+ if (converter->buffer_dur != -1)
+ IMFSample_SetSampleDuration(samples[0].pSample, converter->buffer_dur);
+
+ samples[0].dwStatus = 0;
+ samples[0].pEvents = NULL;
+
+ done:
+ if (buffer)
+ IMFMediaBuffer_Release(buffer);
+ if (FAILED(hr) && allocated_sample)
+ {
+ IMFSample_Release(allocated_sample);
+ samples[0].pSample = NULL;
+ }
+ LeaveCriticalSection(&converter->cs);
+ return hr;
+}
+
+static const IMFTransformVtbl color_converter_vtbl =
+{
+ color_converter_QueryInterface,
+ color_converter_AddRef,
+ color_converter_Release,
+ color_converter_GetStreamLimits,
+ color_converter_GetStreamCount,
+ color_converter_GetStreamIDs,
+ color_converter_GetInputStreamInfo,
+ color_converter_GetOutputStreamInfo,
+ color_converter_GetAttributes,
+ color_converter_GetInputStreamAttributes,
+ color_converter_GetOutputStreamAttributes,
+ color_converter_DeleteInputStream,
+ color_converter_AddInputStreams,
+ color_converter_GetInputAvailableType,
+ color_converter_GetOutputAvailableType,
+ color_converter_SetInputType,
+ color_converter_SetOutputType,
+ color_converter_GetInputCurrentType,
+ color_converter_GetOutputCurrentType,
+ color_converter_GetInputStatus,
+ color_converter_GetOutputStatus,
+ color_converter_SetOutputBounds,
+ color_converter_ProcessEvent,
+ color_converter_ProcessMessage,
+ color_converter_ProcessInput,
+ color_converter_ProcessOutput,
+};
+
+HRESULT color_converter_create(REFIID riid, void **ret)
+{
+ struct color_converter *object;
+
+ TRACE("%s %p\n", debugstr_guid(riid), ret);
+
+ if (!(object = calloc(1, sizeof(*object))))
+ return E_OUTOFMEMORY;
+
+ object->IMFTransform_iface.lpVtbl = &color_converter_vtbl;
+ object->refcount = 1;
+
+ InitializeCriticalSection(&object->cs);
+ object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": color_converter_lock");
+
+ if (!(object->parser = wg_parser_create(WG_PARSER_VIDEOCONV, true)))
+ {
+ ERR("Failed to create video converter due to GStreamer error.\n");
+ IMFTransform_Release(&object->IMFTransform_iface);
+ return E_OUTOFMEMORY;
+ }
+
+ *ret = &object->IMFTransform_iface;
+ return S_OK;
+}
diff --git a/dlls/mfplat/decode_transform.c b/dlls/mfplat/decode_transform.c
new file mode 100644
index 00000000000..fb7f432923f
--- /dev/null
+++ wine/dlls/mfplat/decode_transform.c
@@ -0,0 +1,1218 @@
+/* GStreamer Decoder Transform
+ *
+ * Copyright 2021 Derek Lesho
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "gst_private.h"
+
+#include "mfapi.h"
+#include "mferror.h"
+#include "mfobjects.h"
+#include "mftransform.h"
+
+#include "wine/debug.h"
+#include "wine/heap.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+const GUID *h264_input_types[] = {&MFVideoFormat_H264};
+/* NV12 comes first https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order . thanks to @vitorhnn */
+const GUID *h264_output_types[] = {&MFVideoFormat_NV12, &MFVideoFormat_I420, &MFVideoFormat_IYUV, &MFVideoFormat_YUY2, &MFVideoFormat_YV12};
+
+const GUID *aac_input_types[] = {&MFAudioFormat_AAC};
+const GUID *aac_output_types[] = {&MFAudioFormat_Float};
+
+static struct decoder_desc
+{
+ const GUID *major_type;
+ const GUID **input_types;
+ unsigned int input_types_count;
+ const GUID **output_types;
+ unsigned int output_types_count;
+} decoder_descs[] =
+{
+ { /* DECODER_TYPE_H264 */
+ &MFMediaType_Video,
+ h264_input_types,
+ ARRAY_SIZE(h264_input_types),
+ h264_output_types,
+ ARRAY_SIZE(h264_output_types),
+ },
+ { /* DECODER_TYPE_AAC */
+ &MFMediaType_Audio,
+ aac_input_types,
+ ARRAY_SIZE(aac_input_types),
+ aac_output_types,
+ ARRAY_SIZE(aac_output_types),
+ }
+};
+
+struct pipeline_event
+{
+ enum
+ {
+ PIPELINE_EVENT_NONE,
+ PIPELINE_EVENT_PARSER_STARTED,
+ PIPELINE_EVENT_READ_REQUEST,
+ } type;
+ union
+ {
+ struct
+ {
+ struct wg_parser_stream *stream;
+ } parser_started;
+ } u;
+};
+
+struct mf_decoder
+{
+ IMFTransform IMFTransform_iface;
+ LONG refcount;
+ enum decoder_type type;
+ IMFMediaType *input_type, *output_type;
+ CRITICAL_SECTION cs, help_cs, event_cs;
+ CONDITION_VARIABLE help_cv, event_cv;
+ BOOL flushing, draining, eos, helper_thread_shutdown, video;
+ HANDLE helper_thread, read_thread;
+ uint64_t offset_tracker;
+ struct wg_parser *wg_parser;
+ struct wg_parser_stream *wg_stream;
+
+ struct
+ {
+ enum
+ {
+ HELP_REQ_NONE,
+ HELP_REQ_START_PARSER,
+ } type;
+ } help_request;
+
+ struct pipeline_event event;
+};
+
+static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface)
+{
+ return CONTAINING_RECORD(iface, struct mf_decoder, IMFTransform_iface);
+}
+
+static HRESULT WINAPI mf_decoder_QueryInterface (IMFTransform *iface, REFIID riid, void **out)
+{
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
+
+ if (IsEqualIID(riid, &IID_IMFTransform) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = iface;
+ IMFTransform_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI mf_decoder_AddRef(IMFTransform *iface)
+{
+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface);
+ ULONG refcount = InterlockedIncrement(&decoder->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI mf_decoder_Release(IMFTransform *iface)
+{
+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface);
+ ULONG refcount = InterlockedDecrement(&decoder->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ if (decoder->input_type)
+ {
+ IMFMediaType_Release(decoder->input_type);
+ decoder->input_type = NULL;
+ }
+
+ if (decoder->output_type)
+ {
+ IMFMediaType_Release(decoder->output_type);
+ decoder->output_type = NULL;
+ }
+
+ if (decoder->wg_parser)
+ {
+ /* NULL wg_parser is possible if the wg_parser creation failed. */
+
+ if (decoder->wg_stream)
+ wg_parser_disconnect(decoder->wg_parser);
+
+ EnterCriticalSection(&decoder->event_cs);
+ decoder->helper_thread_shutdown = TRUE;
+ WakeAllConditionVariable(&decoder->event_cv);
+ LeaveCriticalSection(&decoder->event_cs);
+
+ EnterCriticalSection(&decoder->help_cs);
+ WakeAllConditionVariable(&decoder->help_cv);
+ LeaveCriticalSection(&decoder->help_cs);
+
+ if (WaitForSingleObject(decoder->helper_thread, 10000) != WAIT_OBJECT_0)
+ FIXME("Failed waiting for helper thread to terminate.\n");
+ CloseHandle(decoder->helper_thread);
+ if (WaitForSingleObject(decoder->read_thread, 10000) != WAIT_OBJECT_0)
+ FIXME("Failed waiting for read thread to terminate.\n");
+ CloseHandle(decoder->read_thread);
+
+ wg_parser_destroy(decoder->wg_parser);
+ }
+
+ DeleteCriticalSection(&decoder->cs);
+ DeleteCriticalSection(&decoder->help_cs);
+ DeleteCriticalSection(&decoder->event_cs);
+
+ heap_free(decoder);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI mf_decoder_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum,
+ DWORD *output_minimum, DWORD *output_maximum)
+{
+ TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum);
+
+ *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI mf_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
+{
+ TRACE("%p %p %p.\n", iface, inputs, outputs);
+
+ *inputs = *outputs = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI mf_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
+ DWORD output_size, DWORD *outputs)
+{
+ TRACE("%p %u %p %u %p.\n", iface, input_size, inputs, output_size, outputs);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI mf_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
+{
+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface);
+
+ TRACE("%p %u %p\n", decoder, id, info);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF;
+ info->cbAlignment = 0;
+ info->cbSize = 0;
+ /* TODO: retrieve following fields from gstreamer */
+ info->hnsMaxLatency = 0;
+ info->cbMaxLookahead = 0;
+ return S_OK;
+}
+
+static HRESULT WINAPI mf_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
+{
+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface);
+ MFT_OUTPUT_STREAM_INFO stream_info = {};
+ GUID output_subtype;
+ UINT64 framesize;
+
+ TRACE("%p %u %p\n", decoder, id, info);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ EnterCriticalSection(&decoder->cs);
+
+ if (!decoder->output_type)
+ {
+ LeaveCriticalSection(&decoder->cs);
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+
+ if (decoder->video)
+ {
+ stream_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
+ MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES;
+ stream_info.cbSize = 0;
+ if (SUCCEEDED(IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &output_subtype)) &&
+ SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_SIZE, &framesize)))
+ {
+ MFCalculateImageSize(&output_subtype, framesize >> 32, (UINT32) framesize, &stream_info.cbSize);
+ }
+ if (!stream_info.cbSize)
+ ERR("Failed to get desired output buffer size\n");
+ }
+ else
+ {
+ stream_info.dwFlags = MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES;
+ stream_info.cbSize = 4;
+ }
+ stream_info.cbAlignment = 0;
+
+ LeaveCriticalSection(&decoder->cs);
+
+ *info = stream_info;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI mf_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
+{
+ FIXME("%p, %p. semi-stub!\n", iface, attributes);
+
+ return MFCreateAttributes(attributes, 0);
+}
+
+static HRESULT WINAPI mf_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ FIXME("%p, %u, %p.\n", iface, id, attributes);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI mf_decoder_GetOutputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ FIXME("%p, %u, %p.\n", iface, id, attributes);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI mf_decoder_DeleteInputStream(IMFTransform *iface, DWORD id)
+{
+ TRACE("%p, %u.\n", iface, id);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI mf_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
+{
+ TRACE("%p, %u, %p.\n", iface, streams, ids);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI mf_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface);
+ IMFMediaType *input_type;
+ HRESULT hr;
+
+ TRACE("%p, %u, %u, %p\n", decoder, id, index, type);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (index >= decoder_descs[decoder->type].input_types_count)
+ return MF_E_NO_MORE_TYPES;
+
+ if (FAILED(hr = MFCreateMediaType(&input_type)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaType_SetGUID(input_type, &MF_MT_MAJOR_TYPE, decoder_descs[decoder->type].major_type)))
+ {
+ IMFMediaType_Release(input_type);
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_SetGUID(input_type, &MF_MT_SUBTYPE, decoder_descs[decoder->type].input_types[index])))
+ {
+ IMFMediaType_Release(input_type);
+ return hr;
+ }
+
+ *type = input_type;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI mf_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface);
+ IMFMediaType *output_type;
+ HRESULT hr;
+
+ TRACE("%p, %u, %u, %p\n", decoder, id, index, type);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (index >= decoder_descs[decoder->type].output_types_count)
+ return MF_E_NO_MORE_TYPES;
+
+ if (FAILED(hr = MFCreateMediaType(&output_type)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaType_SetGUID(output_type, &MF_MT_MAJOR_TYPE, decoder_descs[decoder->type].major_type)))
+ {
+ IMFMediaType_Release(output_type);
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_SetGUID(output_type, &MF_MT_SUBTYPE, decoder_descs[decoder->type].output_types[index])))
+ {
+ IMFMediaType_Release(output_type);
+ return hr;
+ }
+
+ *type = output_type;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface);
+ struct wg_format input_format;
+ GUID major_type, subtype;
+ unsigned int i;
+ HRESULT hr;
+
+ TRACE("%p, %u, %p, %#x.\n", decoder, id, type, flags);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (!type)
+ {
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ return S_OK;
+
+ EnterCriticalSection(&decoder->cs);
+
+ if (decoder->wg_stream)
+ {
+ decoder->wg_stream = NULL;
+ wg_parser_disconnect(decoder->wg_parser);
+ }
+
+ if (decoder->input_type)
+ {
+ IMFMediaType_Release(decoder->input_type);
+ decoder->input_type = NULL;
+ }
+
+ LeaveCriticalSection(&decoder->cs);
+
+ return S_OK;
+ }
+
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type)))
+ return MF_E_INVALIDTYPE;
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ return MF_E_INVALIDTYPE;
+
+ if (!(IsEqualGUID(&major_type, decoder_descs[decoder->type].major_type)))
+ return MF_E_INVALIDTYPE;
+
+ for (i = 0; i < decoder_descs[decoder->type].input_types_count; i++)
+ {
+ if (IsEqualGUID(&subtype, decoder_descs[decoder->type].input_types[i]))
+ break;
+ if (i == decoder_descs[decoder->type].input_types_count)
+ return MF_E_INVALIDTYPE;
+ }
+
+ mf_media_type_to_wg_format(type, &input_format);
+ if (!input_format.major_type)
+ return MF_E_INVALIDTYPE;
+
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ return S_OK;
+
+ EnterCriticalSection(&decoder->cs);
+
+ hr = S_OK;
+
+ if (decoder->wg_stream)
+ {
+ decoder->wg_stream = NULL;
+ wg_parser_disconnect(decoder->wg_parser);
+ }
+
+ if (!decoder->input_type)
+ hr = MFCreateMediaType(&decoder->input_type);
+
+ if (SUCCEEDED(hr) && FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes*) decoder->input_type)))
+ {
+ IMFMediaType_Release(decoder->input_type);
+ decoder->input_type = NULL;
+ }
+
+ if (decoder->input_type && decoder->output_type)
+ {
+ EnterCriticalSection(&decoder->help_cs);
+ while(decoder->help_request.type != HELP_REQ_NONE)
+ SleepConditionVariableCS(&decoder->help_cv, &decoder->help_cs, INFINITE);
+ decoder->help_request.type = HELP_REQ_START_PARSER;
+ LeaveCriticalSection(&decoder->help_cs);
+ WakeAllConditionVariable(&decoder->help_cv);
+ }
+
+ LeaveCriticalSection(&decoder->cs);
+ return hr;
+}
+
+static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface);
+ struct wg_format output_format;
+ GUID major_type, subtype;
+ HRESULT hr;
+ unsigned int i;
+
+ TRACE("%p, %u, %p, %#x.\n", decoder, id, type, flags);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (!type)
+ {
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ return S_OK;
+
+ EnterCriticalSection(&decoder->cs);
+
+ if (decoder->wg_stream)
+ {
+ decoder->wg_stream = NULL;
+ wg_parser_disconnect(decoder->wg_parser);
+ }
+
+ if (decoder->output_type)
+ {
+ IMFMediaType_Release(decoder->output_type);
+ decoder->output_type = NULL;
+ }
+
+ LeaveCriticalSection(&decoder->cs);
+
+ return S_OK;
+ }
+
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type)))
+ return MF_E_INVALIDTYPE;
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ return MF_E_INVALIDTYPE;
+
+ if (!(IsEqualGUID(&major_type, decoder_descs[decoder->type].major_type)))
+ return MF_E_INVALIDTYPE;
+
+ for (i = 0; i < decoder_descs[decoder->type].output_types_count; i++)
+ {
+ if (IsEqualGUID(&subtype, decoder_descs[decoder->type].output_types[i]))
+ break;
+ if (i == decoder_descs[decoder->type].output_types_count)
+ return MF_E_INVALIDTYPE;
+ }
+
+ mf_media_type_to_wg_format(type, &output_format);
+ if (!output_format.major_type)
+ return MF_E_INVALIDTYPE;
+
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ return S_OK;
+
+ EnterCriticalSection(&decoder->cs);
+
+ hr = S_OK;
+
+ if (decoder->wg_stream)
+ {
+ decoder->wg_stream = NULL;
+ wg_parser_disconnect(decoder->wg_parser);
+ }
+
+ if (!decoder->output_type)
+ hr = MFCreateMediaType(&decoder->output_type);
+
+ if (SUCCEEDED(hr) && FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes*) decoder->output_type)))
+ {
+ IMFMediaType_Release(decoder->output_type);
+ decoder->output_type = NULL;
+ }
+
+ if (decoder->input_type && decoder->output_type)
+ {
+ EnterCriticalSection(&decoder->help_cs);
+ while(decoder->help_request.type != HELP_REQ_NONE)
+ SleepConditionVariableCS(&decoder->help_cv, &decoder->help_cs, INFINITE);
+ decoder->help_request.type = HELP_REQ_START_PARSER;
+ LeaveCriticalSection(&decoder->help_cs);
+ WakeAllConditionVariable(&decoder->help_cv);
+ }
+
+ LeaveCriticalSection(&decoder->cs);
+ return hr;
+}
+
+static HRESULT WINAPI mf_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ FIXME("%p, %u, %p.\n", iface, id, type);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI mf_decoder_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ FIXME("%p, %u, %p.\n", iface, id, type);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI mf_decoder_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
+{
+ FIXME("%p, %u, %p\n", iface, id, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI mf_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags)
+{
+ FIXME("%p, %p.\n", iface, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI mf_decoder_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
+{
+ FIXME("%p, %s, %s.\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper));
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI mf_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
+{
+ FIXME("%p, %u, %p.\n", iface, id, event);
+
+ return E_NOTIMPL;
+}
+
+static DWORD CALLBACK helper_thread_func(PVOID ctx)
+{
+ struct mf_decoder *decoder = (struct mf_decoder *)ctx;
+
+ for(;;)
+ {
+ EnterCriticalSection(&decoder->help_cs);
+
+ while(!decoder->helper_thread_shutdown && decoder->help_request.type == HELP_REQ_NONE)
+ SleepConditionVariableCS(&decoder->help_cv, &decoder->help_cs, INFINITE);
+ if (decoder->helper_thread_shutdown)
+ {
+ LeaveCriticalSection(&decoder->help_cs);
+ return 0;
+ }
+
+ switch(decoder->help_request.type)
+ {
+ case HELP_REQ_START_PARSER:
+ {
+ struct wg_format input_format, output_format;
+ struct wg_rect wg_aperture = {0};
+ MFVideoArea *aperture = NULL;
+ UINT32 aperture_size;
+
+ decoder->help_request.type = HELP_REQ_NONE;
+ LeaveCriticalSection(&decoder->help_cs);
+
+ mf_media_type_to_wg_format(decoder->input_type, &input_format);
+ mf_media_type_to_wg_format(decoder->output_type, &output_format);
+
+ if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(decoder->output_type,
+ &MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8 **) &aperture, &aperture_size)))
+ {
+ TRACE("Decoded media's aperture: x: %u %u/65536, y: %u %u/65536, area: %u x %u\n",
+ aperture->OffsetX.value, aperture->OffsetX.fract,
+ aperture->OffsetY.value, aperture->OffsetY.fract, aperture->Area.cx, aperture->Area.cy);
+
+ /* TODO: verify aperture params? */
+
+ wg_aperture.left = aperture->OffsetX.value;
+ wg_aperture.top = aperture->OffsetY.value;
+ wg_aperture.right = aperture->Area.cx;
+ wg_aperture.bottom = aperture->Area.cy;
+
+ CoTaskMemFree(aperture);
+ }
+
+ wg_parser_connect_unseekable(decoder->wg_parser,
+ &input_format, 1, &output_format, aperture ? &wg_aperture : NULL);
+
+ EnterCriticalSection(&decoder->event_cs);
+ while (!decoder->helper_thread_shutdown && decoder->event.type != PIPELINE_EVENT_NONE)
+ SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE);
+
+ if (decoder->helper_thread_shutdown)
+ {
+ LeaveCriticalSection(&decoder->event_cs);
+ return 0;
+ }
+
+ decoder->event.type = PIPELINE_EVENT_PARSER_STARTED;
+ decoder->event.u.parser_started.stream = wg_parser_get_stream(decoder->wg_parser, 0);
+
+ LeaveCriticalSection(&decoder->event_cs);
+ WakeAllConditionVariable(&decoder->event_cv);
+
+ break;
+ }
+ default:
+ assert(0);
+ }
+ }
+}
+
+/* We use a separate thread to wait for reads, as we may want to wait to WAIT_ANY
+ on a read and another event. */
+static DWORD CALLBACK read_thread_func(PVOID ctx)
+{
+ struct mf_decoder *decoder = (struct mf_decoder *)ctx;
+ uint64_t offset;
+ uint32_t size;
+
+ for (;;)
+ {
+ if (decoder->helper_thread_shutdown)
+ break;
+
+ if (!wg_parser_get_next_read_offset(decoder->wg_parser, &offset, &size))
+ continue;
+
+ EnterCriticalSection(&decoder->event_cs);
+ while (!decoder->helper_thread_shutdown && decoder->event.type != PIPELINE_EVENT_NONE)
+ SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE);
+
+ if (decoder->helper_thread_shutdown)
+ {
+ LeaveCriticalSection(&decoder->event_cs);
+ break;
+ }
+
+ decoder->event.type = PIPELINE_EVENT_READ_REQUEST;
+ WakeAllConditionVariable(&decoder->event_cv);
+ while (!decoder->helper_thread_shutdown && decoder->event.type == PIPELINE_EVENT_READ_REQUEST)
+ SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE);
+ LeaveCriticalSection(&decoder->event_cs);
+ }
+
+ return 0;
+}
+
+static struct pipeline_event get_pipeline_event(struct mf_decoder *decoder)
+{
+ struct pipeline_event ret;
+
+ EnterCriticalSection(&decoder->event_cs);
+ while(decoder->event.type == PIPELINE_EVENT_NONE)
+ SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE);
+
+ ret = decoder->event;
+
+ if (ret.type != PIPELINE_EVENT_READ_REQUEST)
+ {
+ decoder->event.type = PIPELINE_EVENT_NONE;
+ WakeAllConditionVariable(&decoder->event_cv);
+ }
+
+ LeaveCriticalSection(&decoder->event_cs);
+
+ return ret;
+}
+
+static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
+{
+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface);
+ HRESULT hr;
+
+ TRACE("%p, %x %lu.\n", decoder, message, param);
+
+ EnterCriticalSection(&decoder->cs);
+ if (!decoder->input_type || !decoder->output_type)
+ {
+ LeaveCriticalSection(&decoder->cs);
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+
+ hr = S_OK;
+
+ switch (message)
+ {
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
+ break;
+ case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
+ {
+ if (param)
+ {
+ hr = MF_E_INVALIDSTREAMNUMBER;
+ break;
+ }
+ if (!decoder->wg_stream)
+ {
+ ERR("End-Of-Stream marked on a decoder MFT which hasn't finished initialization\n");
+ hr = E_FAIL;
+ break;
+ }
+
+ decoder->eos = TRUE;
+ break;
+ }
+ case MFT_MESSAGE_COMMAND_DRAIN:
+ {
+ struct pipeline_event pip_event;
+
+ if (!decoder->wg_stream)
+ {
+ ERR("Drain requested on a decoder MFT which hasn't finished initialization\n");
+ hr = E_FAIL;
+ break;
+ }
+
+ pip_event = get_pipeline_event(decoder);
+ assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST);
+
+ wg_parser_push_data(decoder->wg_parser, WG_READ_EOS, NULL, 0);
+
+ EnterCriticalSection(&decoder->event_cs);
+ decoder->event.type = PIPELINE_EVENT_NONE;
+ LeaveCriticalSection(&decoder->event_cs);
+ WakeAllConditionVariable(&decoder->event_cv);
+
+ decoder->draining = TRUE;
+ decoder->offset_tracker = 0;
+ break;
+ }
+ case MFT_MESSAGE_COMMAND_FLUSH:
+ {
+ struct pipeline_event pip_event;
+
+ if (!decoder->wg_stream)
+ {
+ ERR("Flush requested on a decoder MFT which hasn't finished initialization\n");
+ hr = E_FAIL;
+ break;
+ }
+
+ pip_event = get_pipeline_event(decoder);
+ assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST);
+
+ wg_parser_push_data(decoder->wg_parser, WG_READ_FLUSHING, NULL, 0);
+
+ EnterCriticalSection(&decoder->event_cs);
+ decoder->event.type = PIPELINE_EVENT_NONE;
+ LeaveCriticalSection(&decoder->event_cs);
+ WakeAllConditionVariable(&decoder->event_cv);
+
+ decoder->offset_tracker = 0;
+ break;
+ }
+ default:
+ {
+ ERR("Unhandled message type %x.\n", message);
+ hr = E_FAIL;
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&decoder->cs);
+ return hr;
+}
+
+static HRESULT WINAPI mf_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
+{
+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface);
+ struct pipeline_event pip_event;
+ IMFMediaBuffer *buffer = NULL;
+ HRESULT hr = S_OK;
+ BYTE *buffer_data;
+ DWORD buffer_size;
+ uint32_t size = 0;
+ uint64_t offset;
+
+ TRACE("%p, %u, %p, %#x.\n", decoder, id, sample, flags);
+
+ if (flags)
+ WARN("Unsupported flags %#x\n", flags);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ EnterCriticalSection(&decoder->cs);
+
+ if (!decoder->input_type || !decoder->output_type)
+ {
+ LeaveCriticalSection(&decoder->cs);
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+
+ if (decoder->draining)
+ {
+ LeaveCriticalSection(&decoder->cs);
+ return MF_E_NOTACCEPTING;
+ }
+
+ if (!decoder->wg_stream)
+ {
+ pip_event = get_pipeline_event(decoder);
+
+ switch (pip_event.type)
+ {
+ case PIPELINE_EVENT_PARSER_STARTED:
+ decoder->wg_stream = pip_event.u.parser_started.stream;
+ break;
+ case PIPELINE_EVENT_READ_REQUEST:
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ if (decoder->wg_stream && !wg_parser_stream_drain(decoder->wg_stream))
+ {
+ LeaveCriticalSection(&decoder->cs);
+ return MF_E_NOTACCEPTING;
+ }
+
+ /* At this point, we either have a pre-init read request, or drained pipeline */
+
+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer)))
+ goto done;
+
+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, &buffer_size)))
+ goto done;
+
+ pip_event = get_pipeline_event(decoder);
+ assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST);
+
+ for(;;)
+ {
+ uint32_t copy_size;
+
+ if (!wg_parser_get_next_read_offset(decoder->wg_parser, &offset, &size))
+ continue;
+
+ copy_size = min(size, buffer_size);
+
+ if (offset != decoder->offset_tracker)
+ {
+ ERR("A seek is needed, MFTs don't support this!\n");
+ wg_parser_push_data(decoder->wg_parser, WG_READ_FAILURE, NULL, 0);
+ IMFMediaBuffer_Unlock(buffer);
+ hr = E_FAIL;
+ goto done;
+ }
+
+ wg_parser_push_data(decoder->wg_parser, WG_READ_SUCCESS, buffer_data, buffer_size);
+
+ decoder->offset_tracker += copy_size;
+
+ if (buffer_size <= size)
+ break;
+
+ buffer_data += copy_size;
+ buffer_size -= copy_size;
+
+ WARN("Input sample split into multiple read requests\n");
+ }
+
+ EnterCriticalSection(&decoder->event_cs);
+ decoder->event.type = PIPELINE_EVENT_NONE;
+ LeaveCriticalSection(&decoder->event_cs);
+ WakeAllConditionVariable(&decoder->event_cv);
+
+ IMFMediaBuffer_Unlock(buffer);
+
+ done:
+ if (buffer)
+ IMFMediaBuffer_Release(buffer);
+ LeaveCriticalSection(&decoder->cs);
+ return hr;
+}
+
+static HRESULT WINAPI mf_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
+{
+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface);
+ MFT_OUTPUT_DATA_BUFFER *relevant_buffer = NULL;
+ struct wg_parser_buffer wg_buffer;
+ struct pipeline_event pip_event;
+ IMFMediaBuffer *buffer;
+ DWORD buffer_len;
+ unsigned int i;
+ BYTE *data;
+ HRESULT hr;
+
+ TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status);
+
+ if (flags)
+ WARN("Unsupported flags %#x\n", flags);
+
+ for (i = 0; i < count; i++)
+ {
+ MFT_OUTPUT_DATA_BUFFER *out_buffer = &samples[i];
+
+ if (out_buffer->dwStreamID != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (relevant_buffer)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ relevant_buffer = out_buffer;
+ }
+
+ if (!relevant_buffer)
+ return S_OK;
+
+ EnterCriticalSection(&decoder->cs);
+
+ if (!decoder->input_type || !decoder->output_type)
+ {
+ LeaveCriticalSection(&decoder->cs);
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+
+ if (!decoder->wg_stream)
+ {
+ pip_event = get_pipeline_event(decoder);
+
+ switch (pip_event.type)
+ {
+ case PIPELINE_EVENT_PARSER_STARTED:
+ decoder->wg_stream = pip_event.u.parser_started.stream;
+ break;
+ case PIPELINE_EVENT_READ_REQUEST:
+ LeaveCriticalSection(&decoder->cs);
+ return MF_E_TRANSFORM_NEED_MORE_INPUT;
+ default:
+ assert(0);
+ }
+ }
+
+ if (wg_parser_stream_drain(decoder->wg_stream))
+ {
+ /* this would be unexpected, as we should get the EOS-event when a drain command completes. */
+ assert (!decoder->draining);
+
+ LeaveCriticalSection(&decoder->cs);
+ return MF_E_TRANSFORM_NEED_MORE_INPUT;
+ }
+
+ if (!wg_parser_stream_get_buffer(decoder->wg_stream, &wg_buffer))
+ {
+ if (!decoder->draining)
+ {
+ LeaveCriticalSection(&decoder->cs);
+ WARN("Received EOS event while not draining\n");
+ return E_FAIL;
+ }
+ decoder->draining = FALSE;
+ LeaveCriticalSection(&decoder->cs);
+ return MF_E_TRANSFORM_NEED_MORE_INPUT;
+ }
+
+ if (relevant_buffer->pSample)
+ {
+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(relevant_buffer->pSample, &buffer)))
+ {
+ ERR("Failed to get buffer from sample, hr %#x.\n", hr);
+ LeaveCriticalSection(&decoder->cs);
+ return hr;
+ }
+ }
+ else
+ {
+ if (FAILED(hr = MFCreateMemoryBuffer(wg_buffer.size, &buffer)))
+ {
+ ERR("Failed to create buffer, hr %#x.\n", hr);
+ LeaveCriticalSection(&decoder->cs);
+ return hr;
+ }
+
+ if (FAILED(hr = MFCreateSample(&relevant_buffer->pSample)))
+ {
+ ERR("Failed to create sample, hr %#x.\n", hr);
+ LeaveCriticalSection(&decoder->cs);
+ IMFMediaBuffer_Release(buffer);
+ return hr;
+ }
+
+ if (FAILED(hr = IMFSample_AddBuffer(relevant_buffer->pSample, buffer)))
+ {
+ ERR("Failed to add buffer, hr %#x.\n", hr);
+ goto out;
+ }
+ }
+
+ if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len)))
+ {
+ ERR("Failed to get buffer size, hr %#x.\n", hr);
+ goto out;
+ }
+
+ if (buffer_len < wg_buffer.size)
+ {
+ WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n",
+ buffer_len, wg_buffer.size);
+
+ if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, buffer_len)))
+ {
+ ERR("Failed to set size, hr %#x.\n", hr);
+ goto out;
+ }
+ }
+ else if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, wg_buffer.size)))
+ {
+ ERR("Failed to set size, hr %#x.\n", hr);
+ goto out;
+ }
+
+
+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL)))
+ {
+ ERR("Failed to lock buffer, hr %#x.\n", hr);
+ goto out;
+ }
+
+ if (!wg_parser_stream_copy_buffer(decoder->wg_stream, data, 0, min(buffer_len, wg_buffer.size)))
+ {
+ hr = E_FAIL;
+ goto out;
+ }
+
+ if (FAILED(hr = IMFMediaBuffer_Unlock(buffer)))
+ {
+ ERR("Failed to unlock buffer, hr %#x.\n", hr);
+ goto out;
+ }
+
+ if (FAILED(hr = IMFSample_SetSampleTime(relevant_buffer->pSample, wg_buffer.pts)))
+ {
+ ERR("Failed to set sample time, hr %#x.\n", hr);
+ goto out;
+ }
+
+ if (FAILED(hr = IMFSample_SetSampleDuration(relevant_buffer->pSample, wg_buffer.duration)))
+ {
+ ERR("Failed to set sample duration, hr %#x.\n", hr);
+ goto out;
+ }
+
+ relevant_buffer->dwStatus = 0;
+ relevant_buffer->pEvents = NULL;
+ *status = 0;
+
+ out:
+ if (SUCCEEDED(hr))
+ wg_parser_stream_release_buffer(decoder->wg_stream);
+ LeaveCriticalSection(&decoder->cs);
+
+ if (FAILED(hr))
+ {
+ IMFSample_Release(relevant_buffer->pSample);
+ relevant_buffer->pSample = NULL;
+ }
+
+ IMFMediaBuffer_Release(buffer);
+
+ return hr;
+}
+
+static const IMFTransformVtbl mf_decoder_vtbl =
+{
+ mf_decoder_QueryInterface,
+ mf_decoder_AddRef,
+ mf_decoder_Release,
+ mf_decoder_GetStreamLimits,
+ mf_decoder_GetStreamCount,
+ mf_decoder_GetStreamIDs,
+ mf_decoder_GetInputStreamInfo,
+ mf_decoder_GetOutputStreamInfo,
+ mf_decoder_GetAttributes,
+ mf_decoder_GetInputStreamAttributes,
+ mf_decoder_GetOutputStreamAttributes,
+ mf_decoder_DeleteInputStream,
+ mf_decoder_AddInputStreams,
+ mf_decoder_GetInputAvailableType,
+ mf_decoder_GetOutputAvailableType,
+ mf_decoder_SetInputType,
+ mf_decoder_SetOutputType,
+ mf_decoder_GetInputCurrentType,
+ mf_decoder_GetOutputCurrentType,
+ mf_decoder_GetInputStatus,
+ mf_decoder_GetOutputStatus,
+ mf_decoder_SetOutputBounds,
+ mf_decoder_ProcessEvent,
+ mf_decoder_ProcessMessage,
+ mf_decoder_ProcessInput,
+ mf_decoder_ProcessOutput,
+};
+
+HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type)
+{
+ struct mf_decoder *object;
+ struct wg_parser *parser;
+
+ TRACE("%s, %p %u.\n", debugstr_guid(riid), obj, type);
+
+ if (!(object = heap_alloc_zero(sizeof(*object))))
+ return E_OUTOFMEMORY;
+
+ object->IMFTransform_iface.lpVtbl = &mf_decoder_vtbl;
+ object->refcount = 1;
+
+ object->type = type;
+ object->video = decoder_descs[type].major_type == &MFMediaType_Video;
+
+ InitializeCriticalSection(&object->cs);
+ InitializeCriticalSection(&object->help_cs);
+ InitializeCriticalSection(&object->event_cs);
+ InitializeConditionVariable(&object->help_cv);
+ InitializeConditionVariable(&object->event_cv);
+
+ if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, TRUE)))
+ {
+ ERR("Failed to create Decoder MFT type %u: Unspecified GStreamer error\n", type);
+ IMFTransform_Release(&object->IMFTransform_iface);
+ return E_OUTOFMEMORY;
+ }
+ object->wg_parser = parser;
+
+ object->helper_thread = CreateThread(NULL, 0, helper_thread_func, object, 0, NULL);
+ object->read_thread = CreateThread(NULL, 0, read_thread_func, object, 0, NULL);
+
+ *obj = &object->IMFTransform_iface;
+ return S_OK;
+}
diff --git a/dlls/mfplat/gst_guids.h b/dlls/mfplat/gst_guids.h
new file mode 100644
index 00000000000..ea859586d7f
--- /dev/null
+++ wine/dlls/mfplat/gst_guids.h
@@ -0,0 +1,23 @@
+/*
+ * GStreamer Guids
+ *
+ * Copyright 2010 Maarten Lankhorst for CodeWeavers
+ * Copyright 2010 Aric Stewart for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+DEFINE_GUID(CLSID_decodebin_parser, 0xf9d8d64e, 0xa144, 0x47dc, 0x8e, 0xe0, 0xf5, 0x34, 0x98, 0x37, 0x2c, 0x29);
+DEFINE_GUID(WINESUBTYPE_Gstreamer, 0xffffffff, 0x128f, 0x4dd1, 0xad, 0x22, 0xbe, 0xcf, 0xa6, 0x6c, 0xe7, 0xaa);
diff --git a/dlls/mfplat/gst_private.h b/dlls/mfplat/gst_private.h
new file mode 100644
index 00000000000..c6b256b4fdd
--- /dev/null
+++ wine/dlls/mfplat/gst_private.h
@@ -0,0 +1,217 @@
+/*
+ * GStreamer splitter + decoder, adapted from parser.c
+ *
+ * Copyright 2010 Maarten Lankhorst for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __GST_PRIVATE_INCLUDED__
+#define __GST_PRIVATE_INCLUDED__
+
+#include <assert.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#define COBJMACROS
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "dshow.h"
+#include "mfidl.h"
+#include "wmsdk.h"
+#include "wine/debug.h"
+#include "wine/strmbase.h"
+
+#include "unixlib.h"
+
+bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) DECLSPEC_HIDDEN;
+
+static inline const char *debugstr_time(REFERENCE_TIME time)
+{
+ ULONGLONG abstime = time >= 0 ? time : -time;
+ unsigned int i = 0, j = 0;
+ char buffer[23], rev[23];
+
+ while (abstime || i <= 8)
+ {
+ buffer[i++] = '0' + (abstime % 10);
+ abstime /= 10;
+ if (i == 7) buffer[i++] = '.';
+ }
+ if (time < 0) buffer[i++] = '-';
+
+ while (i--) rev[j++] = buffer[i];
+ while (rev[j-1] == '0' && rev[j-2] != '.') --j;
+ rev[j] = 0;
+
+ return wine_dbg_sprintf("%s", rev);
+}
+
+#define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000)
+
+struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering) DECLSPEC_HIDDEN;
+void wg_parser_destroy(struct wg_parser *parser) DECLSPEC_HIDDEN;
+
+HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) DECLSPEC_HIDDEN;
+HRESULT wg_parser_connect_unseekable(struct wg_parser *parser, const struct wg_format *in_format,
+ uint32_t stream_count, const struct wg_format *out_formats, const struct wg_rect *apertures) DECLSPEC_HIDDEN;
+void wg_parser_disconnect(struct wg_parser *parser) DECLSPEC_HIDDEN;
+
+bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size) DECLSPEC_HIDDEN;
+void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size) DECLSPEC_HIDDEN;
+
+uint32_t wg_parser_get_stream_count(struct wg_parser *parser) DECLSPEC_HIDDEN;
+struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index) DECLSPEC_HIDDEN;
+
+void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format) DECLSPEC_HIDDEN;
+void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture, uint32_t flags) DECLSPEC_HIDDEN;
+void wg_parser_stream_disable(struct wg_parser_stream *stream) DECLSPEC_HIDDEN;
+
+bool wg_parser_stream_get_buffer(struct wg_parser_stream *stream, struct wg_parser_buffer *buffer) DECLSPEC_HIDDEN;
+bool wg_parser_stream_copy_buffer(struct wg_parser_stream *stream,
+ void *data, uint32_t offset, uint32_t size) DECLSPEC_HIDDEN;
+void wg_parser_stream_release_buffer(struct wg_parser_stream *stream) DECLSPEC_HIDDEN;
+void wg_parser_stream_notify_qos(struct wg_parser_stream *stream,
+ bool underflow, double proportion, int64_t diff, uint64_t timestamp) DECLSPEC_HIDDEN;
+
+/* Returns the duration in 100-nanosecond units. */
+uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) DECLSPEC_HIDDEN;
+bool wg_parser_stream_get_language(struct wg_parser_stream *stream, char *buffer, uint32_t size) DECLSPEC_HIDDEN;
+/* start_pos and stop_pos are in 100-nanosecond units. */
+void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate,
+ uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) DECLSPEC_HIDDEN;
+bool wg_parser_stream_drain(struct wg_parser_stream *stream) DECLSPEC_HIDDEN;
+
+struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_format,
+ const struct wg_format *output_format) DECLSPEC_HIDDEN;
+void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN;
+HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, uint32_t size) DECLSPEC_HIDDEN;
+HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample) DECLSPEC_HIDDEN;
+
+unsigned int wg_format_get_max_size(const struct wg_format *format);
+
+HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
+HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
+HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
+HRESULT wave_parser_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
+HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
+
+bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm);
+bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format);
+
+BOOL init_gstreamer(void) DECLSPEC_HIDDEN;
+
+extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
+extern HRESULT mfplat_DllRegisterServer(void) DECLSPEC_HIDDEN;
+
+IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) DECLSPEC_HIDDEN;
+void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) DECLSPEC_HIDDEN;
+void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_format *format) DECLSPEC_HIDDEN;
+
+HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
+
+HRESULT aac_decoder_create(REFIID riid, void **ret) DECLSPEC_HIDDEN;
+HRESULT h264_decoder_create(REFIID riid, void **ret) DECLSPEC_HIDDEN;
+HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN;
+HRESULT color_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN;
+
+enum decoder_type
+{
+ DECODER_TYPE_H264,
+ DECODER_TYPE_AAC,
+};
+HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type) DECLSPEC_HIDDEN;
+
+struct wm_stream
+{
+ struct wm_reader *reader;
+ struct wg_parser_stream *wg_stream;
+ struct wg_format format;
+ WMT_STREAM_SELECTION selection;
+ WORD index;
+ bool eos;
+ bool allocate_output;
+ bool allocate_stream;
+ /* Note that we only pretend to read compressed samples, and instead output
+ * uncompressed samples regardless of whether we are configured to read
+ * compressed samples. Rather, the behaviour of the reader objects differs
+ * in nontrivial ways depending on this field. */
+ bool read_compressed;
+};
+
+struct wm_reader
+{
+ IWMHeaderInfo3 IWMHeaderInfo3_iface;
+ IWMLanguageList IWMLanguageList_iface;
+ IWMPacketSize2 IWMPacketSize2_iface;
+ IWMProfile3 IWMProfile3_iface;
+ IWMReaderPlaylistBurn IWMReaderPlaylistBurn_iface;
+ IWMReaderTimecode IWMReaderTimecode_iface;
+ LONG refcount;
+ CRITICAL_SECTION cs;
+
+ QWORD start_time;
+
+ IStream *source_stream;
+ HANDLE file;
+ HANDLE read_thread;
+ bool read_thread_shutdown;
+ struct wg_parser *wg_parser;
+
+ struct wm_stream *streams;
+ WORD stream_count;
+
+ IWMReaderCallbackAdvanced *callback_advanced;
+
+ const struct wm_reader_ops *ops;
+};
+
+struct wm_reader_ops
+{
+ void *(*query_interface)(struct wm_reader *reader, REFIID iid);
+ void (*destroy)(struct wm_reader *reader);
+};
+
+void wm_reader_cleanup(struct wm_reader *reader);
+HRESULT wm_reader_close(struct wm_reader *reader);
+HRESULT wm_reader_get_max_stream_size(struct wm_reader *reader, WORD stream_number, DWORD *size);
+HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output,
+ DWORD index, IWMOutputMediaProps **props);
+HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output, DWORD *count);
+HRESULT wm_reader_get_output_props(struct wm_reader *reader, DWORD output,
+ IWMOutputMediaProps **props);
+struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader,
+ WORD stream_number);
+HRESULT wm_reader_get_stream_sample(struct wm_reader *reader, WORD stream_number,
+ INSSBuffer **ret_sample, QWORD *pts, QWORD *duration, DWORD *flags, WORD *ret_stream_number);
+HRESULT wm_reader_get_stream_selection(struct wm_reader *reader,
+ WORD stream_number, WMT_STREAM_SELECTION *selection);
+void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops);
+HRESULT wm_reader_open_file(struct wm_reader *reader, const WCHAR *filename);
+HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream);
+void wm_reader_seek(struct wm_reader *reader, QWORD start, LONGLONG duration);
+HRESULT wm_reader_set_allocate_for_output(struct wm_reader *reader, DWORD output, BOOL allocate);
+HRESULT wm_reader_set_allocate_for_stream(struct wm_reader *reader, WORD stream_number, BOOL allocate);
+HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output,
+ IWMOutputMediaProps *props);
+HRESULT wm_reader_set_read_compressed(struct wm_reader *reader,
+ WORD stream_number, BOOL compressed);
+HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count,
+ const WORD *stream_numbers, const WMT_STREAM_SELECTION *selections);
+
+#endif /* __GST_PRIVATE_INCLUDED__ */
diff --git a/dlls/mfplat/h264_decoder.c b/dlls/mfplat/h264_decoder.c
new file mode 100644
index 00000000000..f6a4d47188f
--- /dev/null
+++ wine/dlls/mfplat/h264_decoder.c
@@ -0,0 +1,727 @@
+/* H264 Decoder Transform
+ *
+ * Copyright 2022 Rémi Bernon for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "gst_private.h"
+
+#include "mfapi.h"
+#include "mferror.h"
+#include "mfobjects.h"
+#include "mftransform.h"
+#include "wmcodecdsp.h"
+
+#include "wine/debug.h"
+#include "wine/heap.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+static const GUID *h264_decoder_input_types[] =
+{
+ &MFVideoFormat_H264,
+};
+static const GUID *h264_decoder_output_types[] =
+{
+ &MFVideoFormat_NV12,
+ &MFVideoFormat_YV12,
+ &MFVideoFormat_IYUV,
+ &MFVideoFormat_I420,
+ &MFVideoFormat_YUY2,
+};
+
+struct h264_decoder
+{
+ IMFTransform IMFTransform_iface;
+ LONG refcount;
+ IMFMediaType *input_type;
+ IMFMediaType *output_type;
+
+ struct wg_transform *wg_transform;
+ struct wg_format wg_format;
+ ULONGLONG last_pts;
+};
+
+static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface)
+{
+ return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface);
+}
+
+static HRESULT try_create_wg_transform(struct h264_decoder *decoder)
+{
+ struct wg_encoded_format input_format;
+ struct wg_format output_format;
+
+ if (decoder->wg_transform)
+ wg_transform_destroy(decoder->wg_transform);
+
+ mf_media_type_to_wg_encoded_format(decoder->input_type, &input_format);
+ if (input_format.encoded_type == WG_ENCODED_TYPE_UNKNOWN)
+ return MF_E_INVALIDMEDIATYPE;
+
+ mf_media_type_to_wg_format(decoder->output_type, &output_format);
+ if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
+ return MF_E_INVALIDMEDIATYPE;
+
+ decoder->last_pts = 0;
+ decoder->wg_transform = wg_transform_create(&input_format, &output_format);
+ if (decoder->wg_transform)
+ return S_OK;
+
+ WARN("Failed to create H264 wg_transform.\n");
+ return E_FAIL;
+}
+
+static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type)
+{
+ UINT32 value, width, height;
+ MFVideoArea aperture = {0};
+ UINT64 value64;
+ GUID subtype;
+ HRESULT hr;
+
+ if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64)))
+ {
+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_FRAME_SIZE, &value64)))
+ value64 = (UINT64)1920 << 32 | 1080;
+ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, value64)))
+ return hr;
+ }
+ width = value64 >> 32;
+ height = value64;
+
+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL)))
+ {
+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_FRAME_RATE, &value64)))
+ value64 = (UINT64)30000 << 32 | 1001;
+ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, value64)))
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL)))
+ {
+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64)))
+ value64 = (UINT64)1 << 32 | 1;
+ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, value64)))
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL)))
+ {
+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_SAMPLE_SIZE, &value)))
+ {
+ if (IsEqualGUID(&subtype, &MFVideoFormat_YUY2))
+ value = width * height * 2;
+ else
+ value = width * height * 3 / 2;
+ }
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value)))
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL)))
+ {
+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_DEFAULT_STRIDE, &value)))
+ {
+ if (IsEqualGUID(&subtype, &MFVideoFormat_YUY2))
+ value = width * 2;
+ else
+ value = width;
+ }
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value)))
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_INTERLACE_MODE, NULL)))
+ {
+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value)))
+ value = MFVideoInterlace_MixedInterlaceOrProgressive;
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_INTERLACE_MODE, value)))
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL)))
+ {
+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value)))
+ value = 1;
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value)))
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL)))
+ {
+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value)))
+ value = 0;
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_VIDEO_ROTATION, value)))
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL)))
+ {
+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value)))
+ value = 1;
+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, value)))
+ return hr;
+ }
+
+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL)))
+ {
+ if (default_type && SUCCEEDED(hr = IMFMediaType_GetBlob(default_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
+ (BYTE *)&aperture, sizeof(aperture), NULL)))
+ {
+ if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
+ (BYTE *)&aperture, sizeof(aperture))))
+ return hr;
+ }
+ }
+
+ return S_OK;
+}
+
+static HRESULT WINAPI h264_decoder_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
+{
+ struct h264_decoder *decoder = impl_from_IMFTransform(iface);
+
+ TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+ if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IMFTransform))
+ *out = &decoder->IMFTransform_iface;
+ else
+ {
+ *out = NULL;
+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown *)*out);
+ return S_OK;
+}
+
+static ULONG WINAPI h264_decoder_AddRef(IMFTransform *iface)
+{
+ struct h264_decoder *decoder = impl_from_IMFTransform(iface);
+ ULONG refcount = InterlockedIncrement(&decoder->refcount);
+
+ TRACE("iface %p increasing refcount to %u.\n", decoder, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI h264_decoder_Release(IMFTransform *iface)
+{
+ struct h264_decoder *decoder = impl_from_IMFTransform(iface);
+ ULONG refcount = InterlockedDecrement(&decoder->refcount);
+
+ TRACE("iface %p decreasing refcount to %u.\n", decoder, refcount);
+
+ if (!refcount)
+ {
+ if (decoder->wg_transform)
+ wg_transform_destroy(decoder->wg_transform);
+ if (decoder->input_type)
+ IMFMediaType_Release(decoder->input_type);
+ if (decoder->output_type)
+ IMFMediaType_Release(decoder->output_type);
+ free(decoder);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI h264_decoder_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum,
+ DWORD *output_minimum, DWORD *output_maximum)
+{
+ FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p stub!\n",
+ iface, input_minimum, input_maximum, output_minimum, output_maximum);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
+{
+ FIXME("iface %p, inputs %p, outputs %p stub!\n", iface, inputs, outputs);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
+ DWORD output_size, DWORD *outputs)
+{
+ FIXME("iface %p, input_size %u, inputs %p, output_size %u, outputs %p stub!\n",
+ iface, input_size, inputs, output_size, outputs);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
+{
+ struct h264_decoder *decoder = impl_from_IMFTransform(iface);
+
+ TRACE("iface %p, id %u, info %p.\n", iface, id, info);
+
+ if (!decoder->input_type)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ info->hnsMaxLatency = 0;
+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE;
+ info->cbSize = 0x1000;
+ info->cbMaxLookahead = 0;
+ info->cbAlignment = 0;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI h264_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
+{
+ struct h264_decoder *decoder = impl_from_IMFTransform(iface);
+ IMFMediaType *media_type;
+ HRESULT hr;
+
+ TRACE("iface %p, id %u, info %p.\n", iface, id, info);
+
+ if (!decoder->input_type || !decoder->output_type)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ media_type = decoder->output_type;
+
+ info->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
+ if (FAILED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &info->cbSize)))
+ info->cbSize = 1920 * 1080 * 2;
+ info->cbAlignment = 0;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI h264_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
+{
+ FIXME("iface %p, attributes %p stub!\n", iface, attributes);
+
+ return MFCreateAttributes(attributes, 0);
+}
+
+static HRESULT WINAPI h264_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ FIXME("iface %p, id %u, attributes %p stub!\n", iface, id, attributes);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_GetOutputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ FIXME("iface %p, id %u, attributes %p stub!\n", iface, id, attributes);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_DeleteInputStream(IMFTransform *iface, DWORD id)
+{
+ FIXME("iface %p, id %u stub!\n", iface, id);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
+{
+ FIXME("iface %p, streams %u, ids %p stub!\n", iface, streams, ids);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ IMFMediaType *media_type;
+ const GUID *subtype;
+ HRESULT hr;
+
+ TRACE("iface %p, id %u, index %u, type %p.\n", iface, id, index, type);
+
+ *type = NULL;
+
+ if (index >= ARRAY_SIZE(h264_decoder_input_types))
+ return MF_E_NO_MORE_TYPES;
+ subtype = h264_decoder_input_types[index];
+
+ if (FAILED(hr = MFCreateMediaType(&media_type)))
+ return hr;
+
+ if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) &&
+ SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype)))
+ IMFMediaType_AddRef((*type = media_type));
+
+ IMFMediaType_Release(media_type);
+ return hr;
+}
+
+static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ struct h264_decoder *decoder = impl_from_IMFTransform(iface);
+ IMFMediaType *media_type;
+ const GUID *output_type;
+ HRESULT hr;
+
+ TRACE("iface %p, id %u, index %u, type %p.\n", iface, id, index, type);
+
+ if (!decoder->input_type)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ *type = NULL;
+
+ if (index >= ARRAY_SIZE(h264_decoder_output_types))
+ return MF_E_NO_MORE_TYPES;
+ output_type = h264_decoder_output_types[index];
+
+ if (FAILED(hr = MFCreateMediaType(&media_type)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
+ goto done;
+ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type)))
+ goto done;
+
+ hr = fill_output_media_type(media_type, decoder->output_type);
+
+done:
+ if (SUCCEEDED(hr))
+ IMFMediaType_AddRef((*type = media_type));
+
+ IMFMediaType_Release(media_type);
+ return hr;
+}
+
+static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ struct h264_decoder *decoder = impl_from_IMFTransform(iface);
+ GUID major, subtype;
+ HRESULT hr;
+ ULONG i;
+
+ TRACE("iface %p, id %u, type %p, flags %#x.\n", iface, id, type, flags);
+
+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ return E_INVALIDARG;
+
+ if (!IsEqualGUID(&major, &MFMediaType_Video))
+ return MF_E_INVALIDMEDIATYPE;
+
+ for (i = 0; i < ARRAY_SIZE(h264_decoder_input_types); ++i)
+ if (IsEqualGUID(&subtype, h264_decoder_input_types[i]))
+ break;
+ if (i == ARRAY_SIZE(h264_decoder_input_types))
+ return MF_E_INVALIDMEDIATYPE;
+
+ if (decoder->output_type)
+ {
+ IMFMediaType_Release(decoder->output_type);
+ decoder->output_type = NULL;
+ }
+
+ if (decoder->input_type)
+ IMFMediaType_Release(decoder->input_type);
+ IMFMediaType_AddRef((decoder->input_type = type));
+
+ return S_OK;
+}
+
+static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ struct h264_decoder *decoder = impl_from_IMFTransform(iface);
+ GUID major, subtype;
+ BOOL identical;
+ HRESULT hr;
+ ULONG i;
+
+ TRACE("iface %p, id %u, type %p, flags %#x.\n", iface, id, type, flags);
+
+ if (!decoder->input_type)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ return hr;
+
+ if (!IsEqualGUID(&major, &MFMediaType_Video))
+ return MF_E_INVALIDMEDIATYPE;
+
+ for (i = 0; i < ARRAY_SIZE(h264_decoder_output_types); ++i)
+ if (IsEqualGUID(&subtype, h264_decoder_output_types[i]))
+ break;
+ if (i == ARRAY_SIZE(h264_decoder_output_types))
+ return MF_E_INVALIDMEDIATYPE;
+
+ if (decoder->output_type)
+ {
+ if (SUCCEEDED(hr = IMFMediaType_Compare(decoder->output_type, (IMFAttributes *)type,
+ MF_ATTRIBUTES_MATCH_THEIR_ITEMS, &identical)) && identical)
+ return S_OK;
+ IMFMediaType_Release(decoder->output_type);
+ }
+
+ IMFMediaType_AddRef((decoder->output_type = type));
+
+ if (FAILED(hr = try_create_wg_transform(decoder)))
+ {
+ IMFMediaType_Release(decoder->output_type);
+ decoder->output_type = NULL;
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI h264_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ FIXME("iface %p, id %u, type %p stub!\n", iface, id, type);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ FIXME("iface %p, id %u, type %p stub!\n", iface, id, type);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
+{
+ FIXME("iface %p, id %u, flags %p stub!\n", iface, id, flags);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags)
+{
+ FIXME("iface %p, flags %p stub!\n", iface, flags);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
+{
+ FIXME("iface %p, lower %s, upper %s stub!\n", iface,
+ wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper));
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
+{
+ FIXME("iface %p, id %u, event %p stub!\n", iface, id, event);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
+{
+ struct h264_decoder *decoder = impl_from_IMFTransform(iface);
+
+ FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param);
+
+ switch (message)
+ {
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ memset(&decoder->wg_format, 0, sizeof(decoder->wg_format));
+ break;
+ default:
+ break;
+ }
+
+ return S_OK;
+}
+
+static HRESULT WINAPI h264_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
+{
+ struct h264_decoder *decoder = impl_from_IMFTransform(iface);
+ IMFMediaBuffer *media_buffer;
+ MFT_INPUT_STREAM_INFO info;
+ UINT32 buffer_size;
+ BYTE *buffer;
+ HRESULT hr;
+
+ TRACE("iface %p, id %u, sample %p, flags %#x.\n", iface, id, sample, flags);
+
+ if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info)))
+ return hr;
+
+ if (!decoder->wg_transform)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, &buffer_size)))
+ goto done;
+
+ hr = wg_transform_push_data(decoder->wg_transform, buffer, buffer_size);
+
+ IMFMediaBuffer_Unlock(media_buffer);
+
+done:
+ IMFMediaBuffer_Release(media_buffer);
+ return hr;
+}
+
+static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
+{
+ struct h264_decoder *decoder = impl_from_IMFTransform(iface);
+ struct wg_sample wg_sample = {0};
+ IMFMediaBuffer *media_buffer;
+ MFT_OUTPUT_STREAM_INFO info;
+ MFVideoArea aperture = {0};
+ IMFMediaType *media_type;
+ UINT32 align, offset;
+ UINT64 framerate;
+ HRESULT hr;
+
+ TRACE("iface %p, flags %#x, count %u, samples %p, status %p.\n", iface, flags, count, samples, status);
+
+ if (count > 1)
+ {
+ FIXME("Not implemented count %u\n", count);
+ return E_NOTIMPL;
+ }
+
+ if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info)))
+ return hr;
+
+ if (!decoder->wg_transform)
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ *status = 0;
+ samples[0].dwStatus = 0;
+ if (!samples[0].pSample)
+ {
+ samples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE;
+ return MF_E_TRANSFORM_NEED_MORE_INPUT;
+ }
+
+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &media_buffer)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &wg_sample.data, &wg_sample.size, NULL)))
+ goto done;
+
+ wg_sample.format = &decoder->wg_format;
+ if (wg_sample.size < info.cbSize)
+ hr = MF_E_BUFFERTOOSMALL;
+ else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample)))
+ {
+ if (!(wg_sample.flags & (WG_SAMPLE_FLAG_HAS_PTS|WG_SAMPLE_FLAG_HAS_DURATION)))
+ {
+ IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &framerate);
+ wg_sample.pts = decoder->last_pts;
+ wg_sample.duration = (UINT64)10000000 * (UINT32)framerate / (framerate >> 32);
+ wg_sample.flags |= (WG_SAMPLE_FLAG_HAS_PTS|WG_SAMPLE_FLAG_HAS_DURATION);
+ decoder->last_pts += wg_sample.duration;
+ }
+
+ if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_PTS)
+ IMFSample_SetSampleTime(samples[0].pSample, wg_sample.pts);
+ if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_DURATION)
+ IMFSample_SetSampleDuration(samples[0].pSample, wg_sample.duration);
+
+ if (decoder->wg_format.u.video.format == WG_VIDEO_FORMAT_NV12 &&
+ (align = decoder->wg_format.u.video.height & 15))
+ {
+ offset = decoder->wg_format.u.video.width * decoder->wg_format.u.video.height;
+ align = (16 - align) * decoder->wg_format.u.video.width;
+ memmove(wg_sample.data + offset + align, wg_sample.data + offset,
+ wg_sample.size - offset);
+ wg_sample.size += align;
+ }
+
+ hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size);
+ }
+ else if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
+ {
+ media_type = mf_media_type_from_wg_format(&decoder->wg_format);
+ IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, wg_sample.size);
+ IMFMediaType_DeleteItem(media_type, &MF_MT_FRAME_RATE);
+ IMFMediaType_DeleteItem(decoder->output_type, &MF_MT_DEFAULT_STRIDE);
+ fill_output_media_type(media_type, decoder->output_type);
+
+ if (decoder->wg_format.u.video.format == WG_VIDEO_FORMAT_NV12 &&
+ (align = decoder->wg_format.u.video.height & 15))
+ {
+ aperture.Area.cx = decoder->wg_format.u.video.width;
+ aperture.Area.cy = decoder->wg_format.u.video.height;
+ IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
+ (BYTE *)&aperture, sizeof(aperture));
+
+ aperture.Area.cy += 16 - align;
+ IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE,
+ (UINT64)aperture.Area.cx << 32 | aperture.Area.cy);
+ IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE,
+ aperture.Area.cx * aperture.Area.cy * 3 / 2);
+ }
+
+ IMFMediaType_Release(decoder->output_type);
+ decoder->output_type = media_type;
+
+ samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
+ *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
+ }
+
+ IMFMediaBuffer_Unlock(media_buffer);
+
+done:
+ if (FAILED(hr))
+ IMFMediaBuffer_SetCurrentLength(media_buffer, 0);
+ IMFMediaBuffer_Release(media_buffer);
+ return hr;
+}
+
+static const IMFTransformVtbl h264_decoder_vtbl =
+{
+ h264_decoder_QueryInterface,
+ h264_decoder_AddRef,
+ h264_decoder_Release,
+ h264_decoder_GetStreamLimits,
+ h264_decoder_GetStreamCount,
+ h264_decoder_GetStreamIDs,
+ h264_decoder_GetInputStreamInfo,
+ h264_decoder_GetOutputStreamInfo,
+ h264_decoder_GetAttributes,
+ h264_decoder_GetInputStreamAttributes,
+ h264_decoder_GetOutputStreamAttributes,
+ h264_decoder_DeleteInputStream,
+ h264_decoder_AddInputStreams,
+ h264_decoder_GetInputAvailableType,
+ h264_decoder_GetOutputAvailableType,
+ h264_decoder_SetInputType,
+ h264_decoder_SetOutputType,
+ h264_decoder_GetInputCurrentType,
+ h264_decoder_GetOutputCurrentType,
+ h264_decoder_GetInputStatus,
+ h264_decoder_GetOutputStatus,
+ h264_decoder_SetOutputBounds,
+ h264_decoder_ProcessEvent,
+ h264_decoder_ProcessMessage,
+ h264_decoder_ProcessInput,
+ h264_decoder_ProcessOutput,
+};
+
+HRESULT h264_decoder_create(REFIID riid, void **ret)
+{
+ struct h264_decoder *decoder;
+
+ TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
+
+ if (!(decoder = calloc(1, sizeof(*decoder))))
+ return E_OUTOFMEMORY;
+
+ decoder->IMFTransform_iface.lpVtbl = &h264_decoder_vtbl;
+ decoder->refcount = 1;
+
+ *ret = &decoder->IMFTransform_iface;
+ TRACE("Created decoder %p\n", *ret);
+ return S_OK;
+}
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index cee052defeb..83fc8549e24 100644
--- wine/dlls/mfplat/main.c
+++ wine/dlls/mfplat/main.c
@@ -36,6 +36,7 @@
#include "d3d11.h"
#include "uuids.h"
+#include "wine/debug.h"
#include "wine/list.h"
#include "mfplat_private.h"
@@ -52,9 +53,6 @@
#include "initguid.h"
#include "mfd3d12.h"
-#include "bcrypt.h"
-#include "pathcch.h"
-
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
struct local_handler
@@ -124,20 +122,17 @@ struct system_time_source
MFCLOCK_STATE state;
IMFClock *clock;
LONGLONG start_offset;
- LONGLONG system_time;
- LONGLONG clock_time;
float rate;
int i_rate;
CRITICAL_SECTION cs;
};
-static void system_time_source_update_clock_time(struct system_time_source *source, LONGLONG system_time)
+static void system_time_source_apply_rate(const struct system_time_source *source, LONGLONG *value)
{
- LONGLONG diff = system_time - source->system_time;
- if (source->i_rate) diff *= source->i_rate;
- else if (source->rate != 1.0f) diff *= source->rate;
- source->clock_time += diff;
- source->system_time = system_time;
+ if (source->i_rate)
+ *value *= source->i_rate;
+ else
+ *value *= source->rate;
}
static struct system_time_source *impl_from_IMFPresentationTimeSource(IMFPresentationTimeSource *iface)
@@ -183,7 +178,7 @@ static ULONG WINAPI transform_activate_AddRef(IMFActivate *iface)
struct transform_activate *activate = impl_from_IMFActivate(iface);
ULONG refcount = InterlockedIncrement(&activate->attributes.ref);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -193,7 +188,7 @@ static ULONG WINAPI transform_activate_Release(IMFActivate *iface)
struct transform_activate *activate = impl_from_IMFActivate(iface);
ULONG refcount = InterlockedDecrement(&activate->attributes.ref);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
{
@@ -707,10 +702,9 @@ static HRESULT register_transform(const CLSID *clsid, const WCHAR *name, UINT32
HRESULT hr = S_OK;
HKEY hclsid = 0;
WCHAR buffer[64];
+ DWORD size, ret;
WCHAR str[250];
UINT8 *blob;
- UINT32 size;
- DWORD ret;
guid_to_string(buffer, clsid);
swprintf(str, ARRAY_SIZE(str), L"%s\\%s", transform_keyW, buffer);
@@ -1196,7 +1190,7 @@ static HRESULT mft_enum(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_INF
if (FAILED(hr = MFGetPluginControl(&plugin_control)))
{
- WARN("Failed to get plugin control instance, hr %#lx.\n", hr);
+ WARN("Failed to get plugin control instance, hr %#x.\n", hr);
return hr;
}
@@ -1519,7 +1513,7 @@ static HRESULT mft_get_attributes(HKEY hkey, IMFAttributes **ret)
if (!RegQueryValueExW(hkey, L"Attributes", NULL, NULL, blob, &size))
{
if (FAILED(hr = MFInitAttributesFromBlob(attributes, blob, size)))
- WARN("Failed to initialize attributes, hr %#lx.\n", hr);
+ WARN("Failed to initialize attributes, hr %#x.\n", hr);
}
free(blob);
@@ -1583,6 +1577,18 @@ HRESULT WINAPI MFTGetInfo(CLSID clsid, WCHAR **name, MFT_REGISTER_TYPE_INFO **in
return hr;
}
+static BOOL CALLBACK register_winegstreamer_proc(INIT_ONCE *once, void *param, void **ctx)
+{
+ HMODULE mod = LoadLibraryW(L"winegstreamer.dll");
+ if (mod)
+ {
+ HRESULT (WINAPI *proc)(void) = (void *)GetProcAddress(mod, "DllRegisterServer");
+ proc();
+ FreeLibrary(mod);
+ }
+ return TRUE;
+}
+
/***********************************************************************
* MFStartup (mfplat.@)
*/
@@ -1590,8 +1596,11 @@ HRESULT WINAPI MFStartup(ULONG version, DWORD flags)
{
#define MF_VERSION_XP MAKELONG( MF_API_VERSION, 1 )
#define MF_VERSION_WIN7 MAKELONG( MF_API_VERSION, 2 )
+ static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
+
+ TRACE("%#x, %#x.\n", version, flags);
- TRACE("%#lx, %#lx.\n", version, flags);
+ InitOnceExecuteOnce(&once, register_winegstreamer_proc, NULL, NULL);
if (version != MF_VERSION_XP && version != MF_VERSION_WIN7)
return MF_E_BAD_STARTUP_VERSION;
@@ -1618,7 +1627,7 @@ HRESULT WINAPI MFShutdown(void)
*/
HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines)
{
- TRACE("%p, %ld, %p, %ld, %lu, %lu.\n", dest, deststride, src, srcstride, width, lines);
+ TRACE("%p, %d, %p, %d, %u, %u.\n", dest, deststride, src, srcstride, width, lines);
while (lines--)
{
@@ -2312,7 +2321,7 @@ static const char *debugstr_eventid(DWORD event)
};
struct event_id *ret = bsearch(&event, event_ids, ARRAY_SIZE(event_ids), sizeof(*event_ids), debug_event_id);
- return ret ? wine_dbg_sprintf("%s", ret->name) : wine_dbg_sprintf("%lu", event);
+ return ret ? wine_dbg_sprintf("%s", ret->name) : wine_dbg_sprintf("%u", event);
}
static inline struct attributes *impl_from_IMFAttributes(IMFAttributes *iface)
@@ -2342,7 +2351,7 @@ static ULONG WINAPI mfattributes_AddRef(IMFAttributes *iface)
struct attributes *attributes = impl_from_IMFAttributes(iface);
ULONG refcount = InterlockedIncrement(&attributes->ref);
- TRACE("%p, refcount %ld.\n", iface, refcount);
+ TRACE("%p, refcount %d.\n", iface, refcount);
return refcount;
}
@@ -2352,7 +2361,7 @@ static ULONG WINAPI mfattributes_Release(IMFAttributes *iface)
struct attributes *attributes = impl_from_IMFAttributes(iface);
ULONG refcount = InterlockedDecrement(&attributes->ref);
- TRACE("%p, refcount %ld.\n", iface, refcount);
+ TRACE("%p, refcount %d.\n", iface, refcount);
if (!refcount)
{
@@ -2670,7 +2679,8 @@ HRESULT attributes_GetAllocatedString(struct attributes *attributes, REFGUID key
if (SUCCEEDED(hr))
{
*value = attrval.pwszVal;
- *length = lstrlenW(*value);
+ if (length)
+ *length = lstrlenW(*value);
}
return hr;
@@ -3730,7 +3740,7 @@ static ULONG WINAPI async_stream_op_AddRef(IUnknown *iface)
struct async_stream_op *op = impl_async_stream_op_from_IUnknown(iface);
ULONG refcount = InterlockedIncrement(&op->refcount);
- TRACE("%p, refcount %ld.\n", iface, refcount);
+ TRACE("%p, refcount %d.\n", iface, refcount);
return refcount;
}
@@ -3740,7 +3750,7 @@ static ULONG WINAPI async_stream_op_Release(IUnknown *iface)
struct async_stream_op *op = impl_async_stream_op_from_IUnknown(iface);
ULONG refcount = InterlockedDecrement(&op->refcount);
- TRACE("%p, refcount %ld.\n", iface, refcount);
+ TRACE("%p, refcount %d.\n", iface, refcount);
if (!refcount)
{
@@ -3902,7 +3912,7 @@ static ULONG WINAPI bytestream_AddRef(IMFByteStream *iface)
struct bytestream *stream = impl_from_IMFByteStream(iface);
ULONG refcount = InterlockedIncrement(&stream->attributes.ref);
- TRACE("%p, refcount %ld.\n", iface, refcount);
+ TRACE("%p, refcount %d.\n", iface, refcount);
return refcount;
}
@@ -3913,7 +3923,7 @@ static ULONG WINAPI bytestream_Release(IMFByteStream *iface)
ULONG refcount = InterlockedDecrement(&stream->attributes.ref);
struct async_stream_op *cur, *cur2;
- TRACE("%p, refcount %ld.\n", iface, refcount);
+ TRACE("%p, refcount %d.\n", iface, refcount);
if (!refcount)
{
@@ -3952,7 +3962,7 @@ static HRESULT WINAPI bytestream_stream_GetCapabilities(IMFByteStream *iface, DW
return S_OK;
}
-static HRESULT WINAPI bytestream_GetCapabilities(IMFByteStream *iface, DWORD *capabilities)
+static HRESULT WINAPI bytestream_file_GetCapabilities(IMFByteStream *iface, DWORD *capabilities)
{
struct bytestream *stream = impl_from_IMFByteStream(iface);
@@ -3963,14 +3973,14 @@ static HRESULT WINAPI bytestream_GetCapabilities(IMFByteStream *iface, DWORD *ca
return S_OK;
}
-static HRESULT WINAPI bytestream_SetLength(IMFByteStream *iface, QWORD length)
+static HRESULT WINAPI bytestream_file_SetLength(IMFByteStream *iface, QWORD length)
{
FIXME("%p, %s\n", iface, wine_dbgstr_longlong(length));
return E_NOTIMPL;
}
-static HRESULT WINAPI bytestream_file_GetCurrentPosition(IMFByteStream *iface, QWORD *position)
+static HRESULT WINAPI bytestream_GetCurrentPosition(IMFByteStream *iface, QWORD *position)
{
struct bytestream *stream = impl_from_IMFByteStream(iface);
@@ -4030,7 +4040,7 @@ static HRESULT WINAPI bytestream_file_Read(IMFByteStream *iface, BYTE *buffer, U
HRESULT hr = S_OK;
BOOL ret;
- TRACE("%p, %p, %lu, %p.\n", iface, buffer, size, read_len);
+ TRACE("%p, %p, %u, %p.\n", iface, buffer, size, read_len);
EnterCriticalSection(&stream->cs);
@@ -4054,7 +4064,7 @@ static HRESULT WINAPI bytestream_BeginRead(IMFByteStream *iface, BYTE *data, ULO
{
struct bytestream *stream = impl_from_IMFByteStream(iface);
- TRACE("%p, %p, %lu, %p, %p.\n", iface, data, size, callback, state);
+ TRACE("%p, %p, %u, %p, %p.\n", iface, data, size, callback, state);
return bytestream_create_io_request(stream, ASYNC_STREAM_OP_READ, data, size, callback, state);
}
@@ -4068,9 +4078,9 @@ static HRESULT WINAPI bytestream_EndRead(IMFByteStream *iface, IMFAsyncResult *r
return bytestream_complete_io_request(stream, ASYNC_STREAM_OP_READ, result, byte_read);
}
-static HRESULT WINAPI bytestream_Write(IMFByteStream *iface, const BYTE *data, ULONG count, ULONG *written)
+static HRESULT WINAPI bytestream_file_Write(IMFByteStream *iface, const BYTE *data, ULONG count, ULONG *written)
{
- FIXME("%p, %p, %lu, %p\n", iface, data, count, written);
+ FIXME("%p, %p, %u, %p\n", iface, data, count, written);
return E_NOTIMPL;
}
@@ -4080,7 +4090,7 @@ static HRESULT WINAPI bytestream_BeginWrite(IMFByteStream *iface, const BYTE *da
{
struct bytestream *stream = impl_from_IMFByteStream(iface);
- TRACE("%p, %p, %lu, %p, %p.\n", iface, data, size, callback, state);
+ TRACE("%p, %p, %u, %p, %p.\n", iface, data, size, callback, state);
return bytestream_create_io_request(stream, ASYNC_STREAM_OP_WRITE, data, size, callback, state);
}
@@ -4094,22 +4104,44 @@ static HRESULT WINAPI bytestream_EndWrite(IMFByteStream *iface, IMFAsyncResult *
return bytestream_complete_io_request(stream, ASYNC_STREAM_OP_WRITE, result, written);
}
-static HRESULT WINAPI bytestream_Seek(IMFByteStream *iface, MFBYTESTREAM_SEEK_ORIGIN seek, LONGLONG offset,
- DWORD flags, QWORD *current)
+static HRESULT WINAPI bytestream_Seek(IMFByteStream *iface, MFBYTESTREAM_SEEK_ORIGIN origin, LONGLONG offset,
+ DWORD flags, QWORD *current)
{
- FIXME("%p, %u, %s, 0x%08lx, %p\n", iface, seek, wine_dbgstr_longlong(offset), flags, current);
+ struct bytestream *stream = impl_from_IMFByteStream(iface);
+ HRESULT hr = S_OK;
- return E_NOTIMPL;
+ TRACE("%p, %u, %s, 0x%08x, %p\n", iface, origin, wine_dbgstr_longlong(offset), flags, current);
+
+ EnterCriticalSection(&stream->cs);
+
+ switch (origin)
+ {
+ case msoBegin:
+ stream->position = offset;
+ break;
+ case msoCurrent:
+ stream->position += offset;
+ break;
+ default:
+ WARN("Unknown origin mode %d.\n", origin);
+ hr = E_INVALIDARG;
+ }
+
+ *current = stream->position;
+
+ LeaveCriticalSection(&stream->cs);
+
+ return hr;
}
-static HRESULT WINAPI bytestream_Flush(IMFByteStream *iface)
+static HRESULT WINAPI bytestream_file_Flush(IMFByteStream *iface)
{
FIXME("%p\n", iface);
return E_NOTIMPL;
}
-static HRESULT WINAPI bytestream_Close(IMFByteStream *iface)
+static HRESULT WINAPI bytestream_file_Close(IMFByteStream *iface)
{
FIXME("%p\n", iface);
@@ -4134,21 +4166,21 @@ static const IMFByteStreamVtbl bytestream_file_vtbl =
bytestream_QueryInterface,
bytestream_AddRef,
bytestream_Release,
- bytestream_GetCapabilities,
+ bytestream_file_GetCapabilities,
bytestream_file_GetLength,
- bytestream_SetLength,
- bytestream_file_GetCurrentPosition,
+ bytestream_file_SetLength,
+ bytestream_GetCurrentPosition,
bytestream_SetCurrentPosition,
bytestream_file_IsEndOfStream,
bytestream_file_Read,
bytestream_BeginRead,
bytestream_EndRead,
- bytestream_Write,
+ bytestream_file_Write,
bytestream_BeginWrite,
bytestream_EndWrite,
bytestream_Seek,
- bytestream_Flush,
- bytestream_Close
+ bytestream_file_Flush,
+ bytestream_file_Close
};
static HRESULT WINAPI bytestream_stream_GetLength(IMFByteStream *iface, QWORD *length)
@@ -4185,17 +4217,6 @@ static HRESULT WINAPI bytestream_stream_SetLength(IMFByteStream *iface, QWORD le
return hr;
}
-static HRESULT WINAPI bytestream_stream_GetCurrentPosition(IMFByteStream *iface, QWORD *position)
-{
- struct bytestream *stream = impl_from_IMFByteStream(iface);
-
- TRACE("%p, %p.\n", iface, position);
-
- *position = stream->position;
-
- return S_OK;
-}
-
static HRESULT WINAPI bytestream_stream_IsEndOfStream(IMFByteStream *iface, BOOL *ret)
{
struct bytestream *stream = impl_from_IMFByteStream(iface);
@@ -4220,7 +4241,7 @@ static HRESULT WINAPI bytestream_stream_Read(IMFByteStream *iface, BYTE *buffer,
LARGE_INTEGER position;
HRESULT hr;
- TRACE("%p, %p, %lu, %p.\n", iface, buffer, size, read_len);
+ TRACE("%p, %p, %u, %p.\n", iface, buffer, size, read_len);
EnterCriticalSection(&stream->cs);
@@ -4242,7 +4263,7 @@ static HRESULT WINAPI bytestream_stream_Write(IMFByteStream *iface, const BYTE *
LARGE_INTEGER position;
HRESULT hr;
- TRACE("%p, %p, %lu, %p.\n", iface, buffer, size, written);
+ TRACE("%p, %p, %u, %p.\n", iface, buffer, size, written);
EnterCriticalSection(&stream->cs);
@@ -4258,36 +4279,6 @@ static HRESULT WINAPI bytestream_stream_Write(IMFByteStream *iface, const BYTE *
return hr;
}
-static HRESULT WINAPI bytestream_stream_Seek(IMFByteStream *iface, MFBYTESTREAM_SEEK_ORIGIN origin, LONGLONG offset,
- DWORD flags, QWORD *current)
-{
- struct bytestream *stream = impl_from_IMFByteStream(iface);
- HRESULT hr = S_OK;
-
- TRACE("%p, %u, %s, %#lx, %p.\n", iface, origin, wine_dbgstr_longlong(offset), flags, current);
-
- EnterCriticalSection(&stream->cs);
-
- switch (origin)
- {
- case msoBegin:
- stream->position = offset;
- break;
- case msoCurrent:
- stream->position += offset;
- break;
- default:
- WARN("Unknown origin mode %d.\n", origin);
- hr = E_INVALIDARG;
- }
-
- *current = stream->position;
-
- LeaveCriticalSection(&stream->cs);
-
- return hr;
-}
-
static HRESULT WINAPI bytestream_stream_Flush(IMFByteStream *iface)
{
struct bytestream *stream = impl_from_IMFByteStream(iface);
@@ -4312,7 +4303,7 @@ static const IMFByteStreamVtbl bytestream_stream_vtbl =
bytestream_stream_GetCapabilities,
bytestream_stream_GetLength,
bytestream_stream_SetLength,
- bytestream_stream_GetCurrentPosition,
+ bytestream_GetCurrentPosition,
bytestream_SetCurrentPosition,
bytestream_stream_IsEndOfStream,
bytestream_stream_Read,
@@ -4321,7 +4312,7 @@ static const IMFByteStreamVtbl bytestream_stream_vtbl =
bytestream_stream_Write,
bytestream_BeginWrite,
bytestream_EndWrite,
- bytestream_stream_Seek,
+ bytestream_Seek,
bytestream_stream_Flush,
bytestream_stream_Close,
};
@@ -4386,11 +4377,10 @@ static const IMFAttributesVtbl bytestream_attributes_vtbl =
mfattributes_CopyAllItems
};
-static HRESULT WINAPI bytestream_stream_read_callback_Invoke(IRtwqAsyncCallback *iface, IRtwqAsyncResult *result)
+static HRESULT WINAPI bytestream_read_callback_Invoke(IRtwqAsyncCallback *iface, IRtwqAsyncResult *result)
{
struct bytestream *stream = impl_from_read_callback_IRtwqAsyncCallback(iface);
struct async_stream_op *op;
- LARGE_INTEGER position;
IUnknown *object;
HRESULT hr;
@@ -4401,13 +4391,8 @@ static HRESULT WINAPI bytestream_stream_read_callback_Invoke(IRtwqAsyncCallback
EnterCriticalSection(&stream->cs);
- position.QuadPart = op->position;
- if (SUCCEEDED(hr = IStream_Seek(stream->stream, position, STREAM_SEEK_SET, NULL)))
- {
- if (SUCCEEDED(hr = IStream_Read(stream->stream, op->u.dest, op->requested_length, &op->actual_length)))
- stream->position += op->actual_length;
- }
-
+ hr = IMFByteStream_Read(&stream->IMFByteStream_iface, op->u.dest, op->requested_length, &op->actual_length);
+ if(FAILED(hr)) TRACE("Read failed: %#lx\n", hr);
IMFAsyncResult_SetStatus(op->caller, hr);
list_add_tail(&stream->pending, &op->entry);
@@ -4418,11 +4403,10 @@ static HRESULT WINAPI bytestream_stream_read_callback_Invoke(IRtwqAsyncCallback
return S_OK;
}
-static HRESULT WINAPI bytestream_stream_write_callback_Invoke(IRtwqAsyncCallback *iface, IRtwqAsyncResult *result)
+static HRESULT WINAPI bytestream_write_callback_Invoke(IRtwqAsyncCallback *iface, IRtwqAsyncResult *result)
{
struct bytestream *stream = impl_from_read_callback_IRtwqAsyncCallback(iface);
struct async_stream_op *op;
- LARGE_INTEGER position;
IUnknown *object;
HRESULT hr;
@@ -4433,13 +4417,8 @@ static HRESULT WINAPI bytestream_stream_write_callback_Invoke(IRtwqAsyncCallback
EnterCriticalSection(&stream->cs);
- position.QuadPart = op->position;
- if (SUCCEEDED(hr = IStream_Seek(stream->stream, position, STREAM_SEEK_SET, NULL)))
- {
- if (SUCCEEDED(hr = IStream_Write(stream->stream, op->u.src, op->requested_length, &op->actual_length)))
- stream->position += op->actual_length;
- }
-
+ hr = IMFByteStream_Write(&stream->IMFByteStream_iface, op->u.src, op->requested_length, &op->actual_length);
+ if(FAILED(hr)) TRACE("Write failed: %#lx\n", hr);
IMFAsyncResult_SetStatus(op->caller, hr);
list_add_tail(&stream->pending, &op->entry);
@@ -4450,22 +4429,22 @@ static HRESULT WINAPI bytestream_stream_write_callback_Invoke(IRtwqAsyncCallback
return S_OK;
}
-static const IRtwqAsyncCallbackVtbl bytestream_stream_read_callback_vtbl =
+static const IRtwqAsyncCallbackVtbl bytestream_read_callback_vtbl =
{
bytestream_callback_QueryInterface,
bytestream_read_callback_AddRef,
bytestream_read_callback_Release,
bytestream_callback_GetParameters,
- bytestream_stream_read_callback_Invoke,
+ bytestream_read_callback_Invoke,
};
-static const IRtwqAsyncCallbackVtbl bytestream_stream_write_callback_vtbl =
+static const IRtwqAsyncCallbackVtbl bytestream_write_callback_vtbl =
{
bytestream_callback_QueryInterface,
bytestream_write_callback_AddRef,
bytestream_write_callback_Release,
bytestream_callback_GetParameters,
- bytestream_stream_write_callback_Invoke,
+ bytestream_write_callback_Invoke,
};
/***********************************************************************
@@ -4491,8 +4470,8 @@ HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **byt
object->IMFByteStream_iface.lpVtbl = &bytestream_stream_vtbl;
object->attributes.IMFAttributes_iface.lpVtbl = &bytestream_attributes_vtbl;
- object->read_callback.lpVtbl = &bytestream_stream_read_callback_vtbl;
- object->write_callback.lpVtbl = &bytestream_stream_write_callback_vtbl;
+ object->read_callback.lpVtbl = &bytestream_read_callback_vtbl;
+ object->write_callback.lpVtbl = &bytestream_write_callback_vtbl;
InitializeCriticalSection(&object->cs);
list_init(&object->pending);
@@ -4516,38 +4495,6 @@ HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **byt
return S_OK;
}
-static HRESULT WINAPI bytestream_file_read_callback_Invoke(IRtwqAsyncCallback *iface, IRtwqAsyncResult *result)
-{
- FIXME("%p, %p.\n", iface, result);
-
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI bytestream_file_write_callback_Invoke(IRtwqAsyncCallback *iface, IRtwqAsyncResult *result)
-{
- FIXME("%p, %p.\n", iface, result);
-
- return E_NOTIMPL;
-}
-
-static const IRtwqAsyncCallbackVtbl bytestream_file_read_callback_vtbl =
-{
- bytestream_callback_QueryInterface,
- bytestream_read_callback_AddRef,
- bytestream_read_callback_Release,
- bytestream_callback_GetParameters,
- bytestream_file_read_callback_Invoke,
-};
-
-static const IRtwqAsyncCallbackVtbl bytestream_file_write_callback_vtbl =
-{
- bytestream_callback_QueryInterface,
- bytestream_write_callback_AddRef,
- bytestream_write_callback_Release,
- bytestream_callback_GetParameters,
- bytestream_file_write_callback_Invoke,
-};
-
static HRESULT WINAPI bytestream_file_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
{
struct bytestream *stream = impl_bytestream_from_IMFGetService(iface);
@@ -4582,8 +4529,11 @@ static const IMFGetServiceVtbl bytestream_file_getservice_vtbl =
bytestream_file_getservice_GetService,
};
-static HRESULT create_file_bytestream(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags,
- const WCHAR *path, BOOL is_tempfile, IMFByteStream **bytestream)
+/***********************************************************************
+ * MFCreateFile (mfplat.@)
+ */
+HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags,
+ LPCWSTR url, IMFByteStream **bytestream)
{
DWORD capabilities = MFBYTESTREAM_IS_SEEKABLE | MFBYTESTREAM_DOES_NOT_USE_NETWORK;
DWORD filecreation_disposition = 0, fileaccessmode = 0, fileattributes = 0;
@@ -4593,6 +4543,8 @@ static HRESULT create_file_bytestream(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPE
HANDLE file;
HRESULT hr;
+ TRACE("%d, %d, %#x, %s, %p.\n", accessmode, openmode, flags, debugstr_w(url), bytestream);
+
switch (accessmode)
{
case MF_ACCESSMODE_READ:
@@ -4631,12 +4583,12 @@ static HRESULT create_file_bytestream(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPE
if (flags & MF_FILEFLAGS_NOBUFFERING)
fileattributes |= FILE_FLAG_NO_BUFFERING;
- if (is_tempfile)
- fileattributes |= FILE_FLAG_DELETE_ON_CLOSE;
/* Open HANDLE to file */
- file = CreateFileW(path, fileaccessmode, filesharemode, NULL, filecreation_disposition, fileattributes, 0);
- if (file == INVALID_HANDLE_VALUE)
+ file = CreateFileW(url, fileaccessmode, filesharemode, NULL,
+ filecreation_disposition, fileattributes, 0);
+
+ if(file == INVALID_HANDLE_VALUE)
return HRESULT_FROM_WIN32(GetLastError());
if (!(object = calloc(1, sizeof(*object))))
@@ -4654,68 +4606,26 @@ static HRESULT create_file_bytestream(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPE
object->IMFByteStream_iface.lpVtbl = &bytestream_file_vtbl;
object->attributes.IMFAttributes_iface.lpVtbl = &bytestream_attributes_vtbl;
object->IMFGetService_iface.lpVtbl = &bytestream_file_getservice_vtbl;
- object->read_callback.lpVtbl = &bytestream_file_read_callback_vtbl;
- object->write_callback.lpVtbl = &bytestream_file_write_callback_vtbl;
+ object->read_callback.lpVtbl = &bytestream_read_callback_vtbl;
+ object->write_callback.lpVtbl = &bytestream_write_callback_vtbl;
InitializeCriticalSection(&object->cs);
list_init(&object->pending);
object->capabilities = capabilities;
object->hfile = file;
- if (!is_tempfile && GetFileTime(file, NULL, NULL, &writetime))
+ if (GetFileTime(file, NULL, NULL, &writetime))
{
IMFAttributes_SetBlob(&object->attributes.IMFAttributes_iface, &MF_BYTESTREAM_LAST_MODIFIED_TIME,
(const UINT8 *)&writetime, sizeof(writetime));
}
- IMFAttributes_SetString(&object->attributes.IMFAttributes_iface, &MF_BYTESTREAM_ORIGIN_NAME, path);
+ IMFAttributes_SetString(&object->attributes.IMFAttributes_iface, &MF_BYTESTREAM_ORIGIN_NAME, url);
*bytestream = &object->IMFByteStream_iface;
return S_OK;
}
-/***********************************************************************
- * MFCreateFile (mfplat.@)
- */
-HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags,
- const WCHAR *path, IMFByteStream **bytestream)
-{
- TRACE("%d, %d, %#x, %s, %p.\n", accessmode, openmode, flags, debugstr_w(path), bytestream);
-
- return create_file_bytestream(accessmode, openmode, flags, path, FALSE, bytestream);
-}
-
-/***********************************************************************
- * MFCreateTempFile (mfplat.@)
- */
-HRESULT WINAPI MFCreateTempFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags,
- IMFByteStream **bytestream)
-{
- WCHAR name[24], tmppath[MAX_PATH], *path;
- ULONG64 rnd;
- size_t len;
- HRESULT hr;
-
- TRACE("%d, %d, %#x, %p.\n", accessmode, openmode, flags, bytestream);
-
- BCryptGenRandom(NULL, (UCHAR *)&rnd, sizeof(rnd), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
- swprintf(name, ARRAY_SIZE(name), L"MFP%llX.TMP", rnd);
- GetTempPathW(ARRAY_SIZE(tmppath), tmppath);
-
- len = wcslen(tmppath) + wcslen(name) + 2;
- if (!(path = malloc(len * sizeof(*path))))
- return E_OUTOFMEMORY;
-
- wcscpy(path, tmppath);
- PathCchAppend(path, len, name);
-
- hr = create_file_bytestream(accessmode, openmode, flags, path, TRUE, bytestream);
-
- free(path);
-
- return hr;
-}
-
struct bytestream_wrapper
{
IMFByteStreamCacheControl IMFByteStreamCacheControl_iface;
@@ -4834,7 +4744,7 @@ static ULONG WINAPI bytestream_wrapper_AddRef(IMFByteStream *iface)
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
ULONG refcount = InterlockedIncrement(&wrapper->refcount);
- TRACE("%p, refcount %ld.\n", iface, refcount);
+ TRACE("%p, refcount %d.\n", iface, refcount);
return refcount;
}
@@ -4844,7 +4754,7 @@ static ULONG WINAPI bytestream_wrapper_Release(IMFByteStream *iface)
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
ULONG refcount = InterlockedDecrement(&wrapper->refcount);
- TRACE("%p, refcount %ld.\n", iface, refcount);
+ TRACE("%p, refcount %d.\n", iface, refcount);
if (!refcount)
{
@@ -4942,7 +4852,7 @@ static HRESULT WINAPI bytestream_wrapper_Read(IMFByteStream *iface, BYTE *data,
{
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
- TRACE("%p, %p, %lu, %p.\n", iface, data, count, byte_read);
+ TRACE("%p, %p, %u, %p.\n", iface, data, count, byte_read);
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
IMFByteStream_Read(wrapper->stream, data, count, byte_read);
@@ -4953,7 +4863,7 @@ static HRESULT WINAPI bytestream_wrapper_BeginRead(IMFByteStream *iface, BYTE *d
{
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
- TRACE("%p, %p, %lu, %p, %p.\n", iface, data, size, callback, state);
+ TRACE("%p, %p, %u, %p, %p.\n", iface, data, size, callback, state);
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
IMFByteStream_BeginRead(wrapper->stream, data, size, callback, state);
@@ -4973,7 +4883,7 @@ static HRESULT WINAPI bytestream_wrapper_Write(IMFByteStream *iface, const BYTE
{
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
- TRACE("%p, %p, %lu, %p.\n", iface, data, count, written);
+ TRACE("%p, %p, %u, %p.\n", iface, data, count, written);
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
IMFByteStream_Write(wrapper->stream, data, count, written);
@@ -4984,7 +4894,7 @@ static HRESULT WINAPI bytestream_wrapper_BeginWrite(IMFByteStream *iface, const
{
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
- TRACE("%p, %p, %lu, %p, %p.\n", iface, data, size, callback, state);
+ TRACE("%p, %p, %u, %p, %p.\n", iface, data, size, callback, state);
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
IMFByteStream_BeginWrite(wrapper->stream, data, size, callback, state);
@@ -5005,7 +4915,7 @@ static HRESULT WINAPI bytestream_wrapper_Seek(IMFByteStream *iface, MFBYTESTREAM
{
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
- TRACE("%p, %u, %s, %#lx, %p.\n", iface, seek, wine_dbgstr_longlong(offset), flags, current);
+ TRACE("%p, %u, %s, %#x, %p.\n", iface, seek, wine_dbgstr_longlong(offset), flags, current);
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
IMFByteStream_Seek(wrapper->stream, seek, offset, flags, current);
@@ -5226,7 +5136,7 @@ static HRESULT WINAPI bytestream_wrapper_events_GetEvent(IMFMediaEventGenerator
{
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFMediaEventGenerator(iface);
- TRACE("%p, %#lx, %p.\n", iface, flags, event);
+ TRACE("%p, %#x, %p.\n", iface, flags, event);
return IMFMediaEventGenerator_GetEvent(wrapper->event_generator, flags, event);
}
@@ -5254,7 +5164,7 @@ static HRESULT WINAPI bytestream_wrapper_events_QueueEvent(IMFMediaEventGenerato
{
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFMediaEventGenerator(iface);
- TRACE("%p, %ld, %s, %#lx, %s.\n", iface, type, debugstr_guid(ext_type), hr, debugstr_propvar(value));
+ TRACE("%p, %d, %s, %#x, %s.\n", iface, type, debugstr_guid(ext_type), hr, debugstr_propvar(value));
return IMFMediaEventGenerator_QueueEvent(wrapper->event_generator, type, ext_type, hr, value);
}
@@ -5357,7 +5267,7 @@ static HRESULT WINAPI bytestream_wrapper_propstore_GetAt(IPropertyStore *iface,
{
struct bytestream_wrapper *wrapper = impl_wrapper_from_IPropertyStore(iface);
- TRACE("%p, %lu, %p.\n", iface, prop, key);
+ TRACE("%p, %u, %p.\n", iface, prop, key);
return IPropertyStore_GetAt(wrapper->propstore, prop, key);
}
@@ -5803,39 +5713,39 @@ static ULONG WINAPI MFPluginControl_Release(IMFPluginControl *iface)
static HRESULT WINAPI MFPluginControl_GetPreferredClsid(IMFPluginControl *iface, DWORD plugin_type,
const WCHAR *selector, CLSID *clsid)
{
- FIXME("(%ld %s %p)\n", plugin_type, debugstr_w(selector), clsid);
+ FIXME("(%d %s %p)\n", plugin_type, debugstr_w(selector), clsid);
return E_NOTIMPL;
}
static HRESULT WINAPI MFPluginControl_GetPreferredClsidByIndex(IMFPluginControl *iface, DWORD plugin_type,
DWORD index, WCHAR **selector, CLSID *clsid)
{
- FIXME("(%ld %ld %p %p)\n", plugin_type, index, selector, clsid);
+ FIXME("(%d %d %p %p)\n", plugin_type, index, selector, clsid);
return E_NOTIMPL;
}
static HRESULT WINAPI MFPluginControl_SetPreferredClsid(IMFPluginControl *iface, DWORD plugin_type,
const WCHAR *selector, const CLSID *clsid)
{
- FIXME("(%ld %s %s)\n", plugin_type, debugstr_w(selector), debugstr_guid(clsid));
+ FIXME("(%d %s %s)\n", plugin_type, debugstr_w(selector), debugstr_guid(clsid));
return E_NOTIMPL;
}
static HRESULT WINAPI MFPluginControl_IsDisabled(IMFPluginControl *iface, DWORD plugin_type, REFCLSID clsid)
{
- FIXME("(%ld %s)\n", plugin_type, debugstr_guid(clsid));
+ FIXME("(%d %s)\n", plugin_type, debugstr_guid(clsid));
return E_NOTIMPL;
}
static HRESULT WINAPI MFPluginControl_GetDisabledByIndex(IMFPluginControl *iface, DWORD plugin_type, DWORD index, CLSID *clsid)
{
- FIXME("(%ld %ld %p)\n", plugin_type, index, clsid);
+ FIXME("(%d %d %p)\n", plugin_type, index, clsid);
return E_NOTIMPL;
}
static HRESULT WINAPI MFPluginControl_SetDisabled(IMFPluginControl *iface, DWORD plugin_type, REFCLSID clsid, BOOL disabled)
{
- FIXME("(%ld %s %x)\n", plugin_type, debugstr_guid(clsid), disabled);
+ FIXME("(%d %s %x)\n", plugin_type, debugstr_guid(clsid), disabled);
return E_NOTIMPL;
}
@@ -6137,9 +6047,8 @@ static const IRtwqAsyncCallbackVtbl source_resolver_callback_url_vtbl =
static HRESULT resolver_create_registered_handler(HKEY hkey, REFIID riid, void **handler)
{
- DWORD name_length, type;
+ unsigned int j = 0, name_length, type;
HRESULT hr = E_FAIL;
- unsigned int j = 0;
WCHAR clsidW[39];
CLSID clsid;
@@ -6162,15 +6071,40 @@ static HRESULT resolver_create_registered_handler(HKEY hkey, REFIID riid, void *
return hr;
}
-static HRESULT resolver_create_bytestream_handler(IMFByteStream *stream, DWORD flags, const WCHAR *mime,
- const WCHAR *extension, IMFByteStreamHandler **handler)
+static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHAR *url, DWORD flags,
+ IMFByteStreamHandler **handler)
{
static const HKEY hkey_roots[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };
+ WCHAR *mimeW = NULL, *urlW = NULL;
+ IMFAttributes *attributes;
+ const WCHAR *url_ext;
HRESULT hr = E_FAIL;
unsigned int i, j;
+ UINT32 length;
*handler = NULL;
+ /* MIME type */
+ if (SUCCEEDED(IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes)))
+ {
+ IMFAttributes_GetAllocatedString(attributes, &MF_BYTESTREAM_CONTENT_TYPE, &mimeW, &length);
+ if (!url)
+ {
+ IMFAttributes_GetAllocatedString(attributes, &MF_BYTESTREAM_ORIGIN_NAME, &urlW, &length);
+ url = urlW;
+ }
+ IMFAttributes_Release(attributes);
+ }
+
+ /* Extension */
+ url_ext = url ? wcsrchr(url, '.') : NULL;
+
+ if (!url_ext && !mimeW)
+ {
+ CoTaskMemFree(urlW);
+ return MF_E_UNSUPPORTED_BYTESTREAM_TYPE;
+ }
+
if (!(flags & MF_RESOLUTION_DISABLE_LOCAL_PLUGINS))
{
struct local_handler *local_handler;
@@ -6179,8 +6113,8 @@ static HRESULT resolver_create_bytestream_handler(IMFByteStream *stream, DWORD f
LIST_FOR_EACH_ENTRY(local_handler, &local_bytestream_handlers, struct local_handler, entry)
{
- if ((mime && !lstrcmpiW(mime, local_handler->u.bytestream.mime))
- || (extension && !lstrcmpiW(extension, local_handler->u.bytestream.extension)))
+ if ((mimeW && !lstrcmpiW(mimeW, local_handler->u.bytestream.mime))
+ || (url_ext && !lstrcmpiW(url_ext, local_handler->u.bytestream.extension)))
{
if (SUCCEEDED(hr = IMFActivate_ActivateObject(local_handler->activate, &IID_IMFByteStreamHandler,
(void **)handler)))
@@ -6191,12 +6125,16 @@ static HRESULT resolver_create_bytestream_handler(IMFByteStream *stream, DWORD f
LeaveCriticalSection(&local_handlers_section);
if (*handler)
+ {
+ CoTaskMemFree(mimeW);
+ CoTaskMemFree(urlW);
return hr;
+ }
}
for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i)
{
- const WCHAR *namesW[2] = { mime, extension };
+ const WCHAR *namesW[2] = { mimeW, url_ext };
HKEY hkey, hkey_handler;
if (RegOpenKeyW(hkey_roots[i], L"Software\\Microsoft\\Windows Media Foundation\\ByteStreamHandlers", &hkey))
@@ -6223,161 +6161,14 @@ static HRESULT resolver_create_bytestream_handler(IMFByteStream *stream, DWORD f
break;
}
- return hr;
-}
-
-static HRESULT resolver_get_bytestream_url_hint(IMFByteStream *stream, WCHAR const **url)
-{
- static const unsigned char asfmagic[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c};
- static const unsigned char wavmagic[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '};
- static const unsigned char wavmask[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
- static const unsigned char isommagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00};
- static const unsigned char mp4_magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', 'S', 'N', 'V',0x00,0x00,0x00,0x00};
- static const unsigned char mp42magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00};
- static const unsigned char mp4vmagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', '4', 'V', ' ',0x00,0x00,0x00,0x00};
- static const unsigned char mp4mask[] = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00};
- static const struct stream_content_url_hint
- {
- const unsigned char *magic;
- const WCHAR *url;
- const unsigned char *mask;
- }
- url_hints[] =
- {
- { asfmagic, L".asf" },
- { wavmagic, L".wav", wavmask },
- { isommagic, L".mp4", mp4mask },
- { mp42magic, L".mp4", mp4mask },
- { mp4_magic, L".mp4", mp4mask },
- { mp4vmagic, L".m4v", mp4mask },
- };
- unsigned char buffer[4 * sizeof(unsigned int)], pattern[4 * sizeof(unsigned int)];
- IMFAttributes *attributes;
- DWORD length = 0, caps = 0;
- unsigned int i, j;
- QWORD position;
- HRESULT hr;
-
- *url = NULL;
-
- if (SUCCEEDED(IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes)))
- {
- UINT32 string_length = 0;
- IMFAttributes_GetStringLength(attributes, &MF_BYTESTREAM_CONTENT_TYPE, &string_length);
- IMFAttributes_Release(attributes);
-
- if (string_length)
- return S_OK;
- }
-
- if (FAILED(hr = IMFByteStream_GetCapabilities(stream, &caps)))
- return hr;
-
- if (!(caps & MFBYTESTREAM_IS_SEEKABLE))
- return MF_E_UNSUPPORTED_BYTESTREAM_TYPE;
-
- if (FAILED(hr = IMFByteStream_GetCurrentPosition(stream, &position)))
- return hr;
-
- hr = IMFByteStream_Read(stream, buffer, sizeof(buffer), &length);
- IMFByteStream_SetCurrentPosition(stream, position);
if (FAILED(hr))
- return hr;
-
- if (length < sizeof(buffer))
- return S_OK;
-
- for (i = 0; i < ARRAY_SIZE(url_hints); ++i)
- {
- memcpy(pattern, buffer, sizeof(buffer));
- if (url_hints[i].mask)
- {
- unsigned int *mask = (unsigned int *)url_hints[i].mask;
- unsigned int *data = (unsigned int *)pattern;
-
- for (j = 0; j < sizeof(buffer) / sizeof(unsigned int); ++j)
- data[j] &= mask[j];
-
- }
- if (!memcmp(pattern, url_hints[i].magic, sizeof(pattern)))
- {
- *url = url_hints[i].url;
- break;
- }
- }
-
- if (*url)
- TRACE("Content type guessed as %s from %s.\n", debugstr_w(*url), debugstr_an((char *)buffer, length));
- else
- WARN("Unrecognized content type %s.\n", debugstr_an((char *)buffer, length));
-
- return S_OK;
-}
-
-static HRESULT resolver_create_gstreamer_handler(IMFByteStreamHandler **handler)
-{
- static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}};
- return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler);
-}
-
-static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHAR *url, DWORD flags,
- IMFByteStreamHandler **handler)
-{
- WCHAR *mimeW = NULL, *urlW = NULL;
- IMFAttributes *attributes;
- const WCHAR *url_ext;
- HRESULT hr = E_FAIL;
- UINT32 length;
-
- *handler = NULL;
-
- /* MIME type */
- if (SUCCEEDED(IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes)))
{
- IMFAttributes_GetAllocatedString(attributes, &MF_BYTESTREAM_CONTENT_TYPE, &mimeW, &length);
- if (!url)
- {
- IMFAttributes_GetAllocatedString(attributes, &MF_BYTESTREAM_ORIGIN_NAME, &urlW, &length);
- url = urlW;
- }
- IMFAttributes_Release(attributes);
- }
-
- /* Extension */
- url_ext = url ? wcsrchr(url, '.') : NULL;
-
- /* If content type was provided by the caller, it's tried first. Otherwise an attempt to deduce
- content type from the content itself is made.
-
- TODO: wine specific fallback to predefined handler could be replaced by normally registering
- this handler for all possible types.
- */
-
- if (url_ext || mimeW)
- {
- hr = resolver_create_bytestream_handler(stream, flags, mimeW, url_ext, handler);
-
- if (FAILED(hr))
- hr = resolver_create_gstreamer_handler(handler);
+ static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}};
+ hr = CoCreateInstance(&CLSID_GStreamerByteStreamHandler, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler);
}
CoTaskMemFree(mimeW);
CoTaskMemFree(urlW);
-
- if (SUCCEEDED(hr))
- return hr;
-
- if (!(flags & MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE))
- return MF_E_UNSUPPORTED_BYTESTREAM_TYPE;
-
- if (FAILED(hr = resolver_get_bytestream_url_hint(stream, &url_ext)))
- return hr;
-
- hr = resolver_create_bytestream_handler(stream, flags, NULL, url_ext, handler);
-
- if (FAILED(hr))
- hr = resolver_create_gstreamer_handler(handler);
-
return hr;
}
@@ -6387,7 +6178,7 @@ static HRESULT resolver_create_scheme_handler(const WCHAR *scheme, DWORD flags,
HRESULT hr = MF_E_UNSUPPORTED_SCHEME;
unsigned int i;
- TRACE("%s, %#lx, %p.\n", debugstr_w(scheme), flags, handler);
+ TRACE("%s, %#x, %p.\n", debugstr_w(scheme), flags, handler);
*handler = NULL;
@@ -6469,11 +6260,10 @@ static HRESULT resolver_get_scheme_handler(const WCHAR *url, DWORD flags, IMFSch
if (ptr == url || *ptr != ':')
{
url = fileschemeW;
- len = ARRAY_SIZE(fileschemeW) - 1;
+ ptr = fileschemeW + ARRAY_SIZE(fileschemeW) - 1;
}
- else
- len = ptr - url + 1;
+ len = ptr - url;
scheme = malloc((len + 1) * sizeof(WCHAR));
if (!scheme)
return E_OUTOFMEMORY;
@@ -6558,7 +6348,7 @@ static ULONG WINAPI source_resolver_AddRef(IMFSourceResolver *iface)
struct source_resolver *resolver = impl_from_IMFSourceResolver(iface);
ULONG refcount = InterlockedIncrement(&resolver->refcount);
- TRACE("%p, refcount %ld.\n", iface, refcount);
+ TRACE("%p, refcount %d.\n", iface, refcount);
return refcount;
}
@@ -6569,7 +6359,7 @@ static ULONG WINAPI source_resolver_Release(IMFSourceResolver *iface)
ULONG refcount = InterlockedDecrement(&resolver->refcount);
struct resolver_queued_result *result, *result2;
- TRACE("%p, refcount %ld.\n", iface, refcount);
+ TRACE("%p, refcount %d.\n", iface, refcount);
if (!refcount)
{
@@ -6596,7 +6386,7 @@ static HRESULT WINAPI source_resolver_CreateObjectFromURL(IMFSourceResolver *ifa
RTWQASYNCRESULT *data;
HRESULT hr;
- TRACE("%p, %s, %#lx, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, obj_type, object);
+ TRACE("%p, %s, %#x, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, obj_type, object);
if (!url || !obj_type || !object)
return E_POINTER;
@@ -6637,7 +6427,7 @@ static HRESULT WINAPI source_resolver_CreateObjectFromByteStream(IMFSourceResolv
RTWQASYNCRESULT *data;
HRESULT hr;
- TRACE("%p, %p, %s, %#lx, %p, %p, %p.\n", iface, stream, debugstr_w(url), flags, props, obj_type, object);
+ TRACE("%p, %p, %s, %#x, %p, %p, %p.\n", iface, stream, debugstr_w(url), flags, props, obj_type, object);
if (!stream || !obj_type || !object)
return E_POINTER;
@@ -6678,7 +6468,7 @@ static HRESULT WINAPI source_resolver_BeginCreateObjectFromURL(IMFSourceResolver
IRtwqAsyncResult *result;
HRESULT hr;
- TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
+ TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
if (FAILED(hr = resolver_get_scheme_handler(url, flags, &handler)))
return hr;
@@ -6722,7 +6512,7 @@ static HRESULT WINAPI source_resolver_BeginCreateObjectFromByteStream(IMFSourceR
IRtwqAsyncResult *result;
HRESULT hr;
- TRACE("%p, %p, %s, %#lx, %p, %p, %p, %p.\n", iface, stream, debugstr_w(url), flags, props, cancel_cookie,
+ TRACE("%p, %p, %s, %#x, %p, %p, %p, %p.\n", iface, stream, debugstr_w(url), flags, props, cancel_cookie,
callback, state);
if (FAILED(hr = resolver_get_bytestream_handler(stream, url, flags, &handler)))
@@ -6868,7 +6658,7 @@ static ULONG WINAPI mfmediaevent_AddRef(IMFMediaEvent *iface)
struct media_event *event = impl_from_IMFMediaEvent(iface);
ULONG refcount = InterlockedIncrement(&event->attributes.ref);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -6878,7 +6668,7 @@ static ULONG WINAPI mfmediaevent_Release(IMFMediaEvent *iface)
struct media_event *event = impl_from_IMFMediaEvent(iface);
ULONG refcount = InterlockedDecrement(&event->attributes.ref);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
{
@@ -7258,7 +7048,7 @@ HRESULT WINAPI MFCreateMediaEvent(MediaEventType type, REFGUID extended_type, HR
struct media_event *object;
HRESULT hr;
- TRACE("%s, %s, %#lx, %s, %p.\n", debugstr_eventid(type), debugstr_guid(extended_type), status,
+ TRACE("%s, %s, %#x, %s, %p.\n", debugstr_eventid(type), debugstr_guid(extended_type), status,
debugstr_propvar(value), event);
object = malloc(sizeof(*object));
@@ -7367,7 +7157,7 @@ static ULONG WINAPI eventqueue_AddRef(IMFMediaEventQueue *iface)
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
ULONG refcount = InterlockedIncrement(&queue->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -7377,7 +7167,7 @@ static ULONG WINAPI eventqueue_Release(IMFMediaEventQueue *iface)
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
ULONG refcount = InterlockedDecrement(&queue->refcount);
- TRACE("%p, refcount %lu.\n", queue, refcount);
+ TRACE("%p, refcount %u.\n", queue, refcount);
if (!refcount)
{
@@ -7542,7 +7332,7 @@ static HRESULT WINAPI eventqueue_QueueEventParamVar(IMFMediaEventQueue *iface, M
IMFMediaEvent *event;
HRESULT hr;
- TRACE("%p, %s, %s, %#lx, %s\n", iface, debugstr_eventid(event_type), debugstr_guid(extended_type), status,
+ TRACE("%p, %s, %s, %#x, %s\n", iface, debugstr_eventid(event_type), debugstr_guid(extended_type), status,
debugstr_propvar(value));
if (FAILED(hr = MFCreateMediaEvent(event_type, extended_type, status, value, &event)))
@@ -7561,7 +7351,7 @@ static HRESULT WINAPI eventqueue_QueueEventParamUnk(IMFMediaEventQueue *iface, M
PROPVARIANT value;
HRESULT hr;
- TRACE("%p, %s, %s, %#lx, %p.\n", iface, debugstr_eventid(event_type), debugstr_guid(extended_type), status, unk);
+ TRACE("%p, %s, %s, %#x, %p.\n", iface, debugstr_eventid(event_type), debugstr_guid(extended_type), status, unk);
value.vt = VT_UNKNOWN;
value.punkVal = unk;
@@ -7684,7 +7474,7 @@ static ULONG WINAPI collection_AddRef(IMFCollection *iface)
struct collection *collection = impl_from_IMFCollection(iface);
ULONG refcount = InterlockedIncrement(&collection->refcount);
- TRACE("%p, %ld.\n", collection, refcount);
+ TRACE("%p, %d.\n", collection, refcount);
return refcount;
}
@@ -7694,7 +7484,7 @@ static ULONG WINAPI collection_Release(IMFCollection *iface)
struct collection *collection = impl_from_IMFCollection(iface);
ULONG refcount = InterlockedDecrement(&collection->refcount);
- TRACE("%p, %ld.\n", collection, refcount);
+ TRACE("%p, %d.\n", collection, refcount);
if (!refcount)
{
@@ -7724,7 +7514,7 @@ static HRESULT WINAPI collection_GetElement(IMFCollection *iface, DWORD idx, IUn
{
struct collection *collection = impl_from_IMFCollection(iface);
- TRACE("%p, %lu, %p.\n", iface, idx, element);
+ TRACE("%p, %u, %p.\n", iface, idx, element);
if (!element)
return E_POINTER;
@@ -7761,7 +7551,7 @@ static HRESULT WINAPI collection_RemoveElement(IMFCollection *iface, DWORD idx,
struct collection *collection = impl_from_IMFCollection(iface);
size_t count;
- TRACE("%p, %lu, %p.\n", iface, idx, element);
+ TRACE("%p, %u, %p.\n", iface, idx, element);
if (!element)
return E_POINTER;
@@ -7784,7 +7574,7 @@ static HRESULT WINAPI collection_InsertElementAt(IMFCollection *iface, DWORD idx
struct collection *collection = impl_from_IMFCollection(iface);
size_t i;
- TRACE("%p, %lu, %p.\n", iface, idx, element);
+ TRACE("%p, %u, %p.\n", iface, idx, element);
if (!mf_array_reserve((void **)&collection->elements, &collection->capacity, idx + 1,
sizeof(*collection->elements)))
@@ -7862,7 +7652,7 @@ HRESULT WINAPI MFCreateCollection(IMFCollection **collection)
*/
void *WINAPI MFHeapAlloc(SIZE_T size, ULONG flags, char *file, int line, EAllocationType type)
{
- TRACE("%Iu, %#lx, %s, %d, %#x.\n", size, flags, debugstr_a(file), line, type);
+ TRACE("%lu, %#x, %s, %d, %#x.\n", size, flags, debugstr_a(file), line, type);
return HeapAlloc(GetProcessHeap(), flags, size);
}
@@ -7907,7 +7697,7 @@ static ULONG WINAPI system_clock_AddRef(IMFClock *iface)
struct system_clock *clock = impl_from_IMFClock(iface);
ULONG refcount = InterlockedIncrement(&clock->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -7917,7 +7707,7 @@ static ULONG WINAPI system_clock_Release(IMFClock *iface)
struct system_clock *clock = impl_from_IMFClock(iface);
ULONG refcount = InterlockedDecrement(&clock->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
free(clock);
@@ -7938,7 +7728,7 @@ static HRESULT WINAPI system_clock_GetClockCharacteristics(IMFClock *iface, DWOR
static HRESULT WINAPI system_clock_GetCorrelatedTime(IMFClock *iface, DWORD reserved, LONGLONG *clock_time,
MFTIME *system_time)
{
- TRACE("%p, %#lx, %p, %p.\n", iface, reserved, clock_time, system_time);
+ TRACE("%p, %#x, %p, %p.\n", iface, reserved, clock_time, system_time);
*clock_time = *system_time = MFGetSystemTime();
@@ -7956,7 +7746,7 @@ static HRESULT WINAPI system_clock_GetContinuityKey(IMFClock *iface, DWORD *key)
static HRESULT WINAPI system_clock_GetState(IMFClock *iface, DWORD reserved, MFCLOCK_STATE *state)
{
- TRACE("%p, %#lx, %p.\n", iface, reserved, state);
+ TRACE("%p, %#x, %p.\n", iface, reserved, state);
*state = MFCLOCK_STATE_RUNNING;
@@ -8036,7 +7826,7 @@ static ULONG WINAPI system_time_source_AddRef(IMFPresentationTimeSource *iface)
struct system_time_source *source = impl_from_IMFPresentationTimeSource(iface);
ULONG refcount = InterlockedIncrement(&source->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -8046,7 +7836,7 @@ static ULONG WINAPI system_time_source_Release(IMFPresentationTimeSource *iface)
struct system_time_source *source = impl_from_IMFPresentationTimeSource(iface);
ULONG refcount = InterlockedDecrement(&source->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
{
@@ -8074,14 +7864,18 @@ static HRESULT WINAPI system_time_source_GetCorrelatedTime(IMFPresentationTimeSo
struct system_time_source *source = impl_from_IMFPresentationTimeSource(iface);
HRESULT hr;
- TRACE("%p, %#lx, %p, %p.\n", iface, reserved, clock_time, system_time);
+ TRACE("%p, %#x, %p, %p.\n", iface, reserved, clock_time, system_time);
EnterCriticalSection(&source->cs);
if (SUCCEEDED(hr = IMFClock_GetCorrelatedTime(source->clock, 0, clock_time, system_time)))
{
if (source->state == MFCLOCK_STATE_RUNNING)
- system_time_source_update_clock_time(source, *system_time);
- *clock_time = source->start_offset + source->clock_time;
+ {
+ system_time_source_apply_rate(source, clock_time);
+ *clock_time += source->start_offset;
+ }
+ else
+ *clock_time = source->start_offset;
}
LeaveCriticalSection(&source->cs);
@@ -8102,7 +7896,7 @@ static HRESULT WINAPI system_time_source_GetState(IMFPresentationTimeSource *ifa
{
struct system_time_source *source = impl_from_IMFPresentationTimeSource(iface);
- TRACE("%p, %#lx, %p.\n", iface, reserved, state);
+ TRACE("%p, %#x, %p.\n", iface, reserved, state);
EnterCriticalSection(&source->cs);
*state = source->state;
@@ -8220,19 +8014,25 @@ static HRESULT WINAPI system_time_source_sink_OnClockStart(IMFClockStateSink *if
state = source->state;
if (SUCCEEDED(hr = system_time_source_change_state(source, CLOCK_CMD_START)))
{
+ system_time_source_apply_rate(source, &system_time);
if (start_offset == PRESENTATION_CURRENT_POSITION)
{
- if (state != MFCLOCK_STATE_RUNNING)
+ switch (state)
{
- source->start_offset -= system_time;
- source->system_time = 0;
+ case MFCLOCK_STATE_RUNNING:
+ break;
+ case MFCLOCK_STATE_PAUSED:
+ source->start_offset -= system_time;
+ break;
+ default:
+ source->start_offset = -system_time;
+ break;
+ ;
}
}
else
{
- source->start_offset = start_offset;
- source->system_time = system_time;
- source->clock_time = 0;
+ source->start_offset = -system_time + start_offset;
}
}
LeaveCriticalSection(&source->cs);
@@ -8249,9 +8049,7 @@ static HRESULT WINAPI system_time_source_sink_OnClockStop(IMFClockStateSink *ifa
EnterCriticalSection(&source->cs);
if (SUCCEEDED(hr = system_time_source_change_state(source, CLOCK_CMD_STOP)))
- {
- source->start_offset = source->system_time = source->clock_time = 0;
- }
+ source->start_offset = 0;
LeaveCriticalSection(&source->cs);
return hr;
@@ -8267,7 +8065,8 @@ static HRESULT WINAPI system_time_source_sink_OnClockPause(IMFClockStateSink *if
EnterCriticalSection(&source->cs);
if (SUCCEEDED(hr = system_time_source_change_state(source, CLOCK_CMD_PAUSE)))
{
- system_time_source_update_clock_time(source, system_time);
+ system_time_source_apply_rate(source, &system_time);
+ source->start_offset += system_time;
}
LeaveCriticalSection(&source->cs);
@@ -8284,7 +8083,8 @@ static HRESULT WINAPI system_time_source_sink_OnClockRestart(IMFClockStateSink *
EnterCriticalSection(&source->cs);
if (SUCCEEDED(hr = system_time_source_change_state(source, CLOCK_CMD_RESTART)))
{
- source->system_time = system_time;
+ system_time_source_apply_rate(source, &system_time);
+ source->start_offset -= system_time;
}
LeaveCriticalSection(&source->cs);
@@ -8399,7 +8199,7 @@ static ULONG WINAPI async_create_file_callback_AddRef(IRtwqAsyncCallback *iface)
struct async_create_file *async = impl_from_create_file_IRtwqAsyncCallback(iface);
ULONG refcount = InterlockedIncrement(&async->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -8409,7 +8209,7 @@ static ULONG WINAPI async_create_file_callback_Release(IRtwqAsyncCallback *iface
struct async_create_file *async = impl_from_create_file_IRtwqAsyncCallback(iface);
ULONG refcount = InterlockedDecrement(&async->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
{
@@ -8696,7 +8496,7 @@ static ULONG WINAPI property_store_AddRef(IPropertyStore *iface)
struct property_store *store = impl_from_IPropertyStore(iface);
ULONG refcount = InterlockedIncrement(&store->refcount);
- TRACE("%p, refcount %ld.\n", iface, refcount);
+ TRACE("%p, refcount %d.\n", iface, refcount);
return refcount;
}
@@ -8706,7 +8506,7 @@ static ULONG WINAPI property_store_Release(IPropertyStore *iface)
struct property_store *store = impl_from_IPropertyStore(iface);
ULONG refcount = InterlockedDecrement(&store->refcount);
- TRACE("%p, refcount %ld.\n", iface, refcount);
+ TRACE("%p, refcount %d.\n", iface, refcount);
if (!refcount)
{
@@ -8737,7 +8537,7 @@ static HRESULT WINAPI property_store_GetAt(IPropertyStore *iface, DWORD index, P
{
struct property_store *store = impl_from_IPropertyStore(iface);
- TRACE("%p, %lu, %p.\n", iface, index, key);
+ TRACE("%p, %u, %p.\n", iface, index, key);
EnterCriticalSection(&store->cs);
@@ -8929,7 +8729,7 @@ static ULONG WINAPI dxgi_device_manager_AddRef(IMFDXGIDeviceManager *iface)
struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
ULONG refcount = InterlockedIncrement(&manager->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -8939,7 +8739,7 @@ static ULONG WINAPI dxgi_device_manager_Release(IMFDXGIDeviceManager *iface)
struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
ULONG refcount = InterlockedDecrement(&manager->refcount);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
{
@@ -9232,9 +9032,21 @@ static const IMFDXGIDeviceManagerVtbl dxgi_device_manager_vtbl =
HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **manager)
{
struct dxgi_device_manager *object;
+ const char *do_not_create = getenv("WINE_DO_NOT_CREATE_DXGI_DEVICE_MANAGER");
TRACE("%p, %p.\n", token, manager);
+ /* Returning a DXGI device manager triggers a bug and breaks The
+ * Long Dark and Trailmakers. This should be removed once CW bug
+ * #19126 is solved. Returning a DXGI device manager also breaks
+ * Age of Empires Definitive Edition - this gameid should be removed
+ * once CW bug #19741 is solved. */
+ if (do_not_create && do_not_create[0] != '\0')
+ {
+ FIXME("stubbing out\n");
+ return E_NOTIMPL;
+ }
+
if (!token || !manager)
return E_POINTER;
@@ -9360,7 +9172,7 @@ static ULONGLONG lldiv128(ULARGE_INTEGER c1, ULARGE_INTEGER c0, LONGLONG denom)
{
ULARGE_INTEGER q1, q0, rhat;
ULARGE_INTEGER v, cmp1, cmp2;
- DWORD s = 0;
+ unsigned int s = 0;
v.QuadPart = llabs(denom);
diff --git a/dlls/mfplat/media_source.c b/dlls/mfplat/media_source.c
new file mode 100644
index 00000000000..82a6da1bcbf
--- /dev/null
+++ wine/dlls/mfplat/media_source.c
@@ -0,0 +1,2006 @@
+/* GStreamer Media Source
+ *
+ * Copyright 2020 Derek Lesho
+ * Copyright 2020 Zebediah Figura for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "gst_private.h"
+
+#include "mfapi.h"
+#include "mferror.h"
+
+#include "wine/list.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+struct media_stream
+{
+ IMFMediaStream IMFMediaStream_iface;
+ LONG ref;
+ struct media_source *parent_source;
+ IMFMediaEventQueue *event_queue;
+ IMFStreamDescriptor *descriptor;
+
+ struct wg_parser_stream *wg_stream;
+
+ IUnknown **token_queue;
+ LONG token_queue_count;
+ LONG token_queue_cap;
+
+ enum
+ {
+ STREAM_INACTIVE,
+ STREAM_SHUTDOWN,
+ STREAM_RUNNING,
+ } state;
+ DWORD stream_id;
+ BOOL eos;
+};
+
+enum source_async_op
+{
+ SOURCE_ASYNC_START,
+ SOURCE_ASYNC_PAUSE,
+ SOURCE_ASYNC_STOP,
+ SOURCE_ASYNC_REQUEST_SAMPLE,
+};
+
+struct source_async_command
+{
+ IUnknown IUnknown_iface;
+ LONG refcount;
+ enum source_async_op op;
+ union
+ {
+ struct
+ {
+ IMFPresentationDescriptor *descriptor;
+ GUID format;
+ PROPVARIANT position;
+ } start;
+ struct
+ {
+ struct media_stream *stream;
+ IUnknown *token;
+ } request_sample;
+ } u;
+};
+
+struct media_source
+{
+ IMFMediaSource IMFMediaSource_iface;
+ IMFGetService IMFGetService_iface;
+ IMFRateSupport IMFRateSupport_iface;
+ IMFRateControl IMFRateControl_iface;
+ IMFAsyncCallback async_commands_callback;
+ LONG ref;
+ DWORD async_commands_queue;
+ IMFMediaEventQueue *event_queue;
+ IMFByteStream *byte_stream;
+
+ struct wg_parser *wg_parser;
+
+ struct media_stream **streams;
+ ULONG stream_count;
+ IMFPresentationDescriptor *pres_desc;
+ enum
+ {
+ SOURCE_OPENING,
+ SOURCE_STOPPED,
+ SOURCE_PAUSED,
+ SOURCE_RUNNING,
+ SOURCE_SHUTDOWN,
+ } state;
+
+ HANDLE read_thread;
+ bool read_thread_shutdown;
+};
+
+static inline struct media_stream *impl_from_IMFMediaStream(IMFMediaStream *iface)
+{
+ return CONTAINING_RECORD(iface, struct media_stream, IMFMediaStream_iface);
+}
+
+static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface)
+{
+ return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
+}
+
+static inline struct media_source *impl_from_IMFGetService(IMFGetService *iface)
+{
+ return CONTAINING_RECORD(iface, struct media_source, IMFGetService_iface);
+}
+
+static inline struct media_source *impl_from_IMFRateSupport(IMFRateSupport *iface)
+{
+ return CONTAINING_RECORD(iface, struct media_source, IMFRateSupport_iface);
+}
+
+static inline struct media_source *impl_from_IMFRateControl(IMFRateControl *iface)
+{
+ return CONTAINING_RECORD(iface, struct media_source, IMFRateControl_iface);
+}
+
+static inline struct media_source *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
+{
+ return CONTAINING_RECORD(iface, struct media_source, async_commands_callback);
+}
+
+static inline struct source_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
+{
+ return CONTAINING_RECORD(iface, struct source_async_command, IUnknown_iface);
+}
+
+static HRESULT WINAPI source_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
+{
+ if (IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IUnknown_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported interface %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI source_async_command_AddRef(IUnknown *iface)
+{
+ struct source_async_command *command = impl_from_async_command_IUnknown(iface);
+ return InterlockedIncrement(&command->refcount);
+}
+
+static ULONG WINAPI source_async_command_Release(IUnknown *iface)
+{
+ struct source_async_command *command = impl_from_async_command_IUnknown(iface);
+ ULONG refcount = InterlockedDecrement(&command->refcount);
+
+ if (!refcount)
+ {
+ if (command->op == SOURCE_ASYNC_START)
+ PropVariantClear(&command->u.start.position);
+ else if (command->op == SOURCE_ASYNC_REQUEST_SAMPLE)
+ {
+ if (command->u.request_sample.token)
+ IUnknown_Release(command->u.request_sample.token);
+ }
+ free(command);
+ }
+
+ return refcount;
+}
+
+static const IUnknownVtbl source_async_command_vtbl =
+{
+ source_async_command_QueryInterface,
+ source_async_command_AddRef,
+ source_async_command_Release,
+};
+
+static HRESULT source_create_async_op(enum source_async_op op, struct source_async_command **ret)
+{
+ struct source_async_command *command;
+
+ if (!(command = calloc(1, sizeof(*command))))
+ return E_OUTOFMEMORY;
+
+ command->IUnknown_iface.lpVtbl = &source_async_command_vtbl;
+ command->op = op;
+
+ *ret = command;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IMFAsyncCallback_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static HRESULT WINAPI callback_GetParameters(IMFAsyncCallback *iface,
+ DWORD *flags, DWORD *queue)
+{
+ return E_NOTIMPL;
+}
+
+static ULONG WINAPI source_async_commands_callback_AddRef(IMFAsyncCallback *iface)
+{
+ struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
+ return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
+}
+
+static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *iface)
+{
+ struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
+ return IMFMediaSource_Release(&source->IMFMediaSource_iface);
+}
+
+static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor *pres_desc, DWORD id, BOOL *selected)
+{
+ ULONG sd_count;
+ IMFStreamDescriptor *ret;
+ unsigned int i;
+
+ if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc, &sd_count)))
+ return NULL;
+
+ for (i = 0; i < sd_count; i++)
+ {
+ DWORD stream_id;
+
+ if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc, i, selected, &ret)))
+ return NULL;
+
+ if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret, &stream_id)) && stream_id == id)
+ return ret;
+
+ IMFStreamDescriptor_Release(ret);
+ }
+ return NULL;
+}
+
+static BOOL enqueue_token(struct media_stream *stream, IUnknown *token)
+{
+ if (stream->token_queue_count == stream->token_queue_cap)
+ {
+ IUnknown **buf;
+ stream->token_queue_cap = stream->token_queue_cap * 2 + 1;
+ buf = realloc(stream->token_queue, stream->token_queue_cap * sizeof(*buf));
+ if (buf)
+ stream->token_queue = buf;
+ else
+ {
+ stream->token_queue_cap = stream->token_queue_count;
+ return FALSE;
+ }
+ }
+ stream->token_queue[stream->token_queue_count++] = token;
+ return TRUE;
+}
+
+static void flush_token_queue(struct media_stream *stream, BOOL send)
+{
+ LONG i;
+
+ for (i = 0; i < stream->token_queue_count; i++)
+ {
+ if (send)
+ {
+ HRESULT hr;
+ struct source_async_command *command;
+ if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command)))
+ {
+ command->u.request_sample.stream = stream;
+ command->u.request_sample.token = stream->token_queue[i];
+
+ hr = MFPutWorkItem(stream->parent_source->async_commands_queue,
+ &stream->parent_source->async_commands_callback, &command->IUnknown_iface);
+ }
+ if (FAILED(hr))
+ WARN("Could not enqueue sample request, hr %#x\n", hr);
+ }
+ else if (stream->token_queue[i])
+ IUnknown_Release(stream->token_queue[i]);
+ }
+ free(stream->token_queue);
+ stream->token_queue = NULL;
+ stream->token_queue_count = 0;
+ stream->token_queue_cap = 0;
+}
+
+static void start_pipeline(struct media_source *source, struct source_async_command *command)
+{
+ PROPVARIANT *position = &command->u.start.position;
+ BOOL seek_message = source->state != SOURCE_STOPPED && position->vt != VT_EMPTY;
+ unsigned int i;
+
+ /* seek to beginning on stop->play */
+ if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY)
+ {
+ position->vt = VT_I8;
+ position->hVal.QuadPart = 0;
+ }
+
+ for (i = 0; i < source->stream_count; i++)
+ {
+ struct media_stream *stream;
+ IMFStreamDescriptor *sd;
+ IMFMediaTypeHandler *mth;
+ IMFMediaType *current_mt;
+ DWORD stream_id;
+ BOOL was_active;
+ BOOL selected;
+
+ stream = source->streams[i];
+
+ IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id);
+
+ sd = stream_descriptor_from_id(command->u.start.descriptor, stream_id, &selected);
+ IMFStreamDescriptor_Release(sd);
+
+ was_active = stream->state != STREAM_INACTIVE;
+
+ stream->state = selected ? STREAM_RUNNING : STREAM_INACTIVE;
+
+ if (selected)
+ {
+ struct wg_format format;
+
+ IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &mth);
+ IMFMediaTypeHandler_GetCurrentMediaType(mth, &current_mt);
+
+ mf_media_type_to_wg_format(current_mt, &format);
+ wg_parser_stream_enable(stream->wg_stream, &format, NULL, 0);
+
+ IMFMediaType_Release(current_mt);
+ IMFMediaTypeHandler_Release(mth);
+ }
+
+ if (position->vt != VT_EMPTY)
+ stream->eos = FALSE;
+
+ if (selected)
+ {
+ TRACE("Stream %u (%p) selected\n", i, stream);
+ IMFMediaEventQueue_QueueEventParamUnk(source->event_queue,
+ was_active ? MEUpdatedStream : MENewStream, &GUID_NULL,
+ S_OK, (IUnknown*) &stream->IMFMediaStream_iface);
+
+ IMFMediaEventQueue_QueueEventParamVar(stream->event_queue,
+ seek_message ? MEStreamSeeked : MEStreamStarted, &GUID_NULL, S_OK, position);
+ }
+ }
+
+ IMFMediaEventQueue_QueueEventParamVar(source->event_queue,
+ seek_message ? MESourceSeeked : MESourceStarted,
+ &GUID_NULL, S_OK, position);
+
+ source->state = SOURCE_RUNNING;
+
+ if (position->vt == VT_I8)
+ wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0, position->hVal.QuadPart, 0,
+ AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
+
+ for (i = 0; i < source->stream_count; i++)
+ flush_token_queue(source->streams[i], position->vt == VT_EMPTY);
+}
+
+static void pause_pipeline(struct media_source *source)
+{
+ unsigned int i;
+
+ for (i = 0; i < source->stream_count; i++)
+ {
+ struct media_stream *stream = source->streams[i];
+ if (stream->state != STREAM_INACTIVE)
+ {
+ IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamPaused, &GUID_NULL, S_OK, NULL);
+ }
+ }
+
+ IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourcePaused, &GUID_NULL, S_OK, NULL);
+
+ source->state = SOURCE_PAUSED;
+}
+
+static void stop_pipeline(struct media_source *source)
+{
+ unsigned int i;
+
+ for (i = 0; i < source->stream_count; i++)
+ {
+ struct media_stream *stream = source->streams[i];
+ if (stream->state != STREAM_INACTIVE)
+ {
+ IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped, &GUID_NULL, S_OK, NULL);
+ wg_parser_stream_disable(stream->wg_stream);
+ }
+ }
+
+ IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL);
+
+ source->state = SOURCE_STOPPED;
+
+ for (i = 0; i < source->stream_count; i++)
+ flush_token_queue(source->streams[i], FALSE);
+}
+
+static void dispatch_end_of_presentation(struct media_source *source)
+{
+ PROPVARIANT empty = {.vt = VT_EMPTY};
+ unsigned int i;
+
+ /* A stream has ended, check whether all have */
+ for (i = 0; i < source->stream_count; i++)
+ {
+ struct media_stream *stream = source->streams[i];
+
+ if (stream->state != STREAM_INACTIVE && !stream->eos)
+ return;
+ }
+
+ IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty);
+}
+
+static void send_buffer(struct media_stream *stream, const struct wg_parser_buffer *wg_buffer, IUnknown *token)
+{
+ IMFMediaBuffer *buffer;
+ IMFSample *sample;
+ HRESULT hr;
+ BYTE *data;
+
+ if (FAILED(hr = MFCreateSample(&sample)))
+ {
+ ERR("Failed to create sample, hr %#x.\n", hr);
+ return;
+ }
+
+ if (FAILED(hr = MFCreateMemoryBuffer(wg_buffer->size, &buffer)))
+ {
+ ERR("Failed to create buffer, hr %#x.\n", hr);
+ IMFSample_Release(sample);
+ return;
+ }
+
+ if (FAILED(hr = IMFSample_AddBuffer(sample, buffer)))
+ {
+ ERR("Failed to add buffer, hr %#x.\n", hr);
+ goto out;
+ }
+
+ if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, wg_buffer->size)))
+ {
+ ERR("Failed to set size, hr %#x.\n", hr);
+ goto out;
+ }
+
+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL)))
+ {
+ ERR("Failed to lock buffer, hr %#x.\n", hr);
+ goto out;
+ }
+
+ if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, wg_buffer->size))
+ {
+ wg_parser_stream_release_buffer(stream->wg_stream);
+ IMFMediaBuffer_Unlock(buffer);
+ goto out;
+ }
+ wg_parser_stream_release_buffer(stream->wg_stream);
+
+ if (FAILED(hr = IMFMediaBuffer_Unlock(buffer)))
+ {
+ ERR("Failed to unlock buffer, hr %#x.\n", hr);
+ goto out;
+ }
+
+ if (FAILED(hr = IMFSample_SetSampleTime(sample, wg_buffer->pts)))
+ {
+ ERR("Failed to set sample time, hr %#x.\n", hr);
+ goto out;
+ }
+
+ if (FAILED(hr = IMFSample_SetSampleDuration(sample, wg_buffer->duration)))
+ {
+ ERR("Failed to set sample duration, hr %#x.\n", hr);
+ goto out;
+ }
+
+ if (token)
+ IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token);
+
+ IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample,
+ &GUID_NULL, S_OK, (IUnknown *)sample);
+
+out:
+ IMFMediaBuffer_Release(buffer);
+ IMFSample_Release(sample);
+}
+
+static void wait_on_sample(struct media_stream *stream, IUnknown *token)
+{
+ PROPVARIANT empty_var = {.vt = VT_EMPTY};
+ struct wg_parser_buffer buffer;
+
+ TRACE("%p, %p\n", stream, token);
+
+ if (wg_parser_stream_get_buffer(stream->wg_stream, &buffer))
+ {
+ send_buffer(stream, &buffer, token);
+ }
+ else
+ {
+ stream->eos = TRUE;
+ IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var);
+ dispatch_end_of_presentation(stream->parent_source);
+ }
+}
+
+static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+ struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
+ struct source_async_command *command;
+ IUnknown *state;
+ HRESULT hr;
+
+ if (source->state == SOURCE_SHUTDOWN)
+ return S_OK;
+
+ if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
+ return hr;
+
+ command = impl_from_async_command_IUnknown(state);
+ switch (command->op)
+ {
+ case SOURCE_ASYNC_START:
+ start_pipeline(source, command);
+ break;
+ case SOURCE_ASYNC_PAUSE:
+ pause_pipeline(source);
+ break;
+ case SOURCE_ASYNC_STOP:
+ stop_pipeline(source);
+ break;
+ case SOURCE_ASYNC_REQUEST_SAMPLE:
+ if (source->state == SOURCE_PAUSED)
+ enqueue_token(command->u.request_sample.stream, command->u.request_sample.token);
+ else
+ wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token);
+ break;
+ }
+
+ IUnknown_Release(state);
+
+ return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl =
+{
+ callback_QueryInterface,
+ source_async_commands_callback_AddRef,
+ source_async_commands_callback_Release,
+ callback_GetParameters,
+ source_async_commands_Invoke,
+};
+
+static DWORD CALLBACK read_thread(void *arg)
+{
+ struct media_source *source = arg;
+ IMFByteStream *byte_stream = source->byte_stream;
+ size_t buffer_size = 4096;
+ uint64_t file_size;
+ void *data;
+
+ if (!(data = malloc(buffer_size)))
+ return 0;
+
+ IMFByteStream_GetLength(byte_stream, &file_size);
+
+ TRACE("Starting read thread for media source %p.\n", source);
+
+ while (!source->read_thread_shutdown)
+ {
+ uint64_t offset;
+ ULONG ret_size;
+ uint32_t size;
+ HRESULT hr;
+
+ if (!wg_parser_get_next_read_offset(source->wg_parser, &offset, &size))
+ continue;
+
+ if (offset >= file_size)
+ size = 0;
+ else if (offset + size >= file_size)
+ size = file_size - offset;
+
+ /* Some IMFByteStreams (including the standard file-based stream) return
+ * an error when reading past the file size. */
+ if (!size)
+ {
+ wg_parser_push_data(source->wg_parser, WG_READ_SUCCESS, data, 0);
+ continue;
+ }
+
+ if (!array_reserve(&data, &buffer_size, size, 1))
+ {
+ free(data);
+ return 0;
+ }
+
+ ret_size = 0;
+
+ if (SUCCEEDED(hr = IMFByteStream_SetCurrentPosition(byte_stream, offset)))
+ hr = IMFByteStream_Read(byte_stream, data, size, &ret_size);
+ if (FAILED(hr))
+ ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr);
+ else if (ret_size != size)
+ ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size);
+ wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, ret_size);
+ }
+
+ free(data);
+ TRACE("Media source is shutting down; exiting.\n");
+ return 0;
+}
+
+static HRESULT WINAPI media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
+
+ if (IsEqualIID(riid, &IID_IMFMediaStream) ||
+ IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = &stream->IMFMediaStream_iface;
+ }
+ else
+ {
+ FIXME("(%s, %p)\n", debugstr_guid(riid), out);
+ *out = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown*)*out);
+ return S_OK;
+}
+
+static ULONG WINAPI media_stream_AddRef(IMFMediaStream *iface)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+ ULONG ref = InterlockedIncrement(&stream->ref);
+
+ TRACE("%p, refcount %u.\n", iface, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI media_stream_Release(IMFMediaStream *iface)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+ ULONG ref = InterlockedDecrement(&stream->ref);
+
+ TRACE("%p, refcount %u.\n", iface, ref);
+
+ if (!ref)
+ {
+ if (stream->event_queue)
+ IMFMediaEventQueue_Release(stream->event_queue);
+ flush_token_queue(stream, FALSE);
+ free(stream);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("%p, %#x, %p.\n", iface, flags, event);
+
+ return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event);
+}
+
+static HRESULT WINAPI media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("%p, %p, %p.\n", iface, callback, state);
+
+ return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state);
+}
+
+static HRESULT WINAPI media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("%p, %p, %p.\n", stream, result, event);
+
+ return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event);
+}
+
+static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type,
+ HRESULT hr, const PROPVARIANT *value)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
+
+ return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value);
+}
+
+static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **source)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("%p, %p.\n", iface, source);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ IMFMediaSource_AddRef(&stream->parent_source->IMFMediaSource_iface);
+ *source = &stream->parent_source->IMFMediaSource_iface;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("%p, %p.\n", iface, descriptor);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ IMFStreamDescriptor_AddRef(stream->descriptor);
+ *descriptor = stream->descriptor;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+ struct source_async_command *command;
+ HRESULT hr;
+
+ TRACE("%p, %p.\n", iface, token);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ if (stream->state == STREAM_INACTIVE)
+ {
+ WARN("Stream isn't active\n");
+ return MF_E_MEDIA_SOURCE_WRONGSTATE;
+ }
+
+ if (stream->eos)
+ {
+ return MF_E_END_OF_STREAM;
+ }
+
+ if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command)))
+ {
+ command->u.request_sample.stream = stream;
+ if (token)
+ IUnknown_AddRef(token);
+ command->u.request_sample.token = token;
+
+ hr = MFPutWorkItem(stream->parent_source->async_commands_queue,
+ &stream->parent_source->async_commands_callback, &command->IUnknown_iface);
+ }
+
+ return hr;
+}
+
+static const IMFMediaStreamVtbl media_stream_vtbl =
+{
+ media_stream_QueryInterface,
+ media_stream_AddRef,
+ media_stream_Release,
+ media_stream_GetEvent,
+ media_stream_BeginGetEvent,
+ media_stream_EndGetEvent,
+ media_stream_QueueEvent,
+ media_stream_GetMediaSource,
+ media_stream_GetStreamDescriptor,
+ media_stream_RequestSample
+};
+
+static HRESULT new_media_stream(struct media_source *source,
+ struct wg_parser_stream *wg_stream, DWORD stream_id, struct media_stream **out_stream)
+{
+ struct media_stream *object = calloc(1, sizeof(*object));
+ HRESULT hr;
+
+ TRACE("source %p, wg_stream %p, stream_id %u.\n", source, wg_stream, stream_id);
+
+ object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl;
+ object->ref = 1;
+
+ if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
+ {
+ free(object);
+ return hr;
+ }
+
+ IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
+ object->parent_source = source;
+ object->stream_id = stream_id;
+
+ object->state = STREAM_INACTIVE;
+ object->eos = FALSE;
+ object->wg_stream = wg_stream;
+
+ TRACE("Created stream object %p.\n", object);
+
+ *out_stream = object;
+
+ return S_OK;
+}
+
+static HRESULT media_stream_init_desc(struct media_stream *stream)
+{
+ IMFMediaTypeHandler *type_handler = NULL;
+ IMFMediaType *stream_types[8];
+ struct wg_format format;
+ DWORD type_count = 0;
+ unsigned int i;
+ HRESULT hr;
+
+ wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
+
+ if (format.major_type == WG_MAJOR_TYPE_VIDEO)
+ {
+ /* These are the most common native output types of decoders:
+ https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order */
+ static const GUID *const video_types[] =
+ {
+ &MFVideoFormat_NV12,
+ &MFVideoFormat_YV12,
+ &MFVideoFormat_YUY2,
+ &MFVideoFormat_IYUV,
+ &MFVideoFormat_I420,
+ &MFVideoFormat_ARGB32,
+ &MFVideoFormat_RGB32,
+ };
+
+ IMFMediaType *base_type = mf_media_type_from_wg_format(&format);
+ GUID base_subtype;
+
+ IMFMediaType_GetGUID(base_type, &MF_MT_SUBTYPE, &base_subtype);
+
+ stream_types[0] = base_type;
+ type_count = 1;
+
+ for (i = 0; i < ARRAY_SIZE(video_types); i++)
+ {
+ IMFMediaType *new_type;
+
+ if (IsEqualGUID(&base_subtype, video_types[i]))
+ continue;
+
+ if (FAILED(hr = MFCreateMediaType(&new_type)))
+ goto done;
+ stream_types[type_count++] = new_type;
+
+ if (FAILED(hr = IMFMediaType_CopyAllItems(base_type, (IMFAttributes *) new_type)))
+ goto done;
+ if (FAILED(hr = IMFMediaType_SetGUID(new_type, &MF_MT_SUBTYPE, video_types[i])))
+ goto done;
+ }
+ }
+ else if (format.major_type == WG_MAJOR_TYPE_AUDIO)
+ {
+ /* Expose at least one PCM and one floating point type for the
+ consumer to pick from. */
+ static const enum wg_audio_format audio_types[] =
+ {
+ WG_AUDIO_FORMAT_S16LE,
+ WG_AUDIO_FORMAT_F32LE,
+ };
+
+ stream_types[0] = mf_media_type_from_wg_format(&format);
+ type_count = 1;
+
+ for (i = 0; i < ARRAY_SIZE(audio_types); i++)
+ {
+ struct wg_format new_format;
+ if (format.u.audio.format == audio_types[i])
+ continue;
+ new_format = format;
+ new_format.u.audio.format = audio_types[i];
+ stream_types[type_count++] = mf_media_type_from_wg_format(&new_format);
+ }
+ }
+ else
+ {
+ if ((stream_types[0] = mf_media_type_from_wg_format(&format)))
+ type_count = 1;
+ }
+
+ assert(type_count <= ARRAY_SIZE(stream_types));
+
+ if (!type_count)
+ {
+ ERR("Failed to establish an IMFMediaType from any of the possible stream caps!\n");
+ return E_FAIL;
+ }
+
+ if (FAILED(hr = MFCreateStreamDescriptor(stream->stream_id, type_count, stream_types, &stream->descriptor)))
+ goto done;
+
+ if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler)))
+ {
+ IMFStreamDescriptor_Release(stream->descriptor);
+ goto done;
+ }
+
+ if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_types[0])))
+ {
+ IMFStreamDescriptor_Release(stream->descriptor);
+ goto done;
+ }
+
+done:
+ if (type_handler)
+ IMFMediaTypeHandler_Release(type_handler);
+ for (i = 0; i < type_count; i++)
+ IMFMediaType_Release(stream_types[i]);
+ return hr;
+}
+
+static HRESULT WINAPI media_source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
+{
+ struct media_source *source = impl_from_IMFGetService(iface);
+ return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
+}
+
+static ULONG WINAPI media_source_get_service_AddRef(IMFGetService *iface)
+{
+ struct media_source *source = impl_from_IMFGetService(iface);
+ return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
+}
+
+static ULONG WINAPI media_source_get_service_Release(IMFGetService *iface)
+{
+ struct media_source *source = impl_from_IMFGetService(iface);
+ return IMFMediaSource_Release(&source->IMFMediaSource_iface);
+}
+
+static HRESULT WINAPI media_source_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
+{
+ struct media_source *source = impl_from_IMFGetService(iface);
+
+ TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
+
+ *obj = NULL;
+
+ if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
+ {
+ if (IsEqualIID(riid, &IID_IMFRateSupport))
+ {
+ *obj = &source->IMFRateSupport_iface;
+
View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment