# Copyright (C) 2023 Apple, Inc.
#
# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
# The 22.1.1 tarball contains an empty sources/freetype directory, which confuses the default CurlDownloadStrategy.
# A custom strategy also allows us to restrict extraction to just the wine subdirectory.
class TarballDownloadStrategy < CurlDownloadStrategy
def stage(&block)
ohai "Staging #{cached_location} in #{pwd}"
system "tar", "-xf", cached_location, "--include=sources/wine/*", "--strip-components=1"
yield if block_given?
end
end
class GamePortingToolkit < Formula
version "1.0.4"
desc "Apple Game Porting Toolkit"
homepage "https://developer.apple.com/"
url "https://media.codeweavers.com/pub/crossover/source/crossover-sources-22.1.1.tar.gz", using: TarballDownloadStrategy
sha256 "cdfe282ce33788bd4f969c8bfb1d3e2de060eb6c296fa1c3cdf4e4690b8b1831"
patch :p0, :DATA
depends_on arch: :x86_64
depends_on "game-porting-toolkit-compiler"
depends_on "bison" => :build
uses_from_macos "flex" => :build
depends_on "mingw-w64" => :build
depends_on "gstreamer"
depends_on "pkg-config" # to find the rest of the runtime dependencies
@@named_deps = ["zlib", # must be explicitly added to PKG_CONFIG_PATH
"freetype",
"sdl2",
"libgphoto2",
"faudio",
"jpeg",
"libpng",
"mpg123",
"libtiff",
"libgsm",
"glib",
"gnutls",
"libusb",
"gettext",
"openssl@1.1",
"sane-backends"]
@@named_deps.each do |dep|
depends_on dep
end
def install
# Bypass the Homebrew shims to build native binaries with the dedicated compiler.
# (PE binaries will be built with mingw32-gcc.)
compiler = Formula["game-porting-toolkit-compiler"]
compiler_options = ["CC=#{compiler.bin}/clang",
"CXX=#{compiler.bin}/clang++"]
# Becuase we are bypassing the Homebrew shims, we need to make the dependencies’ headers visible.
# (mingw32-gcc will automatically make the mingw-w64 headers visible.)
@@named_deps.each do |dep|
formula = Formula[dep]
ENV.append_to_cflags "-I#{formula.include}"
ENV.append "LDFLAGS", "-L#{formula.lib}"
end
# Glib & GStreamer have also has a non-standard include path
ENV.append "GSTREAMER_CFLAGS", "-I#{Formula['gstreamer'].include}/gstreamer-1.0"
ENV.append "GSTREAMER_LIBS", "-L#{Formula['gstreamer'].lib}"
ENV.append "GSTREAMER_CFLAGS", "-I#{Formula['glib'].include}/glib-2.0"
ENV.append "GSTREAMER_CFLAGS", "-I#{Formula['glib'].lib}/glib-2.0/include"
ENV.append "GSTREAMER_LIBS", "-lglib-2.0 -lgmodule-2.0 -lgstreamer-1.0 -lgstaudio-1.0 -lgstvideo-1.0 -lgstgl-1.0 -lgobject-2.0"
# We also need to tell the linker to add Homebrew to the rpath stack.
ENV.append "LDFLAGS", "-lSystem -L#{HOMEBREW_PREFIX}/lib -Wl,-rpath,#{HOMEBREW_PREFIX}/lib -Wl,-rpath,@executable_path/../lib/external"
# Common compiler flags for both Mach-O and PE binaries.
ENV.append_to_cflags "-O3 -Wno-implicit-function-declaration -Wno-format -Wno-deprecated-declarations -Wno-incompatible-pointer-types"
# Use an older deployment target to avoid new dyld behaviors.
# The custom compiler is too old to accept "13.0", so we use "10.14".
ENV["MACOSX_DEPLOYMENT_TARGET"] = "10.14"
wine_configure_options = ["--prefix=#{prefix}",
"--disable-win16",
"--disable-tests",
"--without-x",
"--without-pulse",
"--without-dbus",
"--without-inotify",
"--without-alsa",
"--without-capi",
"--without-oss",
"--without-udev",
"--without-krb5"]
wine64_configure_options = ["--enable-win64",
"--with-gnutls",
"--with-freetype",
"--with-gstreamer"]
wine32_configure_options = ["--enable-win32on64",
"--with-wine64=../wine64-build",
"--without-gstreamer",
"--without-gphoto",
"--without-sane",
"--without-krb5",
"--disable-winedbg",
"--without-vulkan",
"--disable-vulkan_1",
"--disable-winevulkan",
"--without-openal",
"--without-unwind",
"--without-usb"]
# Build 64-bit Wine first.
mkdir buildpath/"wine64-build" do
system buildpath/"wine/configure", *wine_configure_options, *wine64_configure_options, *compiler_options
system "make"
end
# Now build 32-on-64 Wine.
mkdir buildpath/"wine32-build" do
system buildpath/"wine/configure", *wine_configure_options, *wine32_configure_options, *compiler_options
system "make"
end
# Install both builds.
cd "wine64-build" do
system "make", "install"
end
cd "wine32-build" do
system "make", "install"
end
end
def post_install
#Homebrew replaces wine's rpath names with absolute paths, we need to change them back to @rpath relative paths.
#Wine relies on @rpath names to cause dlopen to always return the first dylib with that name loaded into the process rather than the actual dylib found using rpath lookup.
Dir["#{lib}/wine/{x86_64-unix,x86_32on64-unix}/*.so"].each do |dylib|
chmod 0664, dylib
MachO::Tools.change_dylib_id(dylib, "@rpath/#{File.basename(dylib)}")
MachO.codesign!(dylib)
chmod 0444, dylib
end
end
def caveats
return unless latest_version_installed?
"Please follow the instructions in the Game Porting Toolkit README to complete installation."
end
test do
system bin/"wine64", "--version"
end
end
__END__
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 http://www.codeweavers.com/compatibility/ 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 file a bug report 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
#include
-#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, ¶);
}
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(¶, 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(¶, 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(¶, 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(¶, 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
@@ -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
+#include
+#include
+
+#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",
+ ARRAY_SIZE(L"Windows.Foundation.IAsyncOperation`1"),
+ 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 */
+ 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",
+ ARRAY_SIZE(L"Windows.Foundation.IAsyncOperation`1"),
+ 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 */
+ 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, ¶ms, 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 */
+ 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;
interface Windows.Foundation.IAsyncOperation;
+ interface Windows.Foundation.Collections.IIterator;
+ interface Windows.Foundation.Collections.IIterable;
interface Windows.Foundation.Collections.IVectorView;
+ interface Windows.Foundation.Collections.IVector;
}
[
@@ -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 **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;
+ }
+
+ [
+ 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 *handler, [out, retval] EventRegistrationToken *token);
+ [eventremove] HRESULT VisibilityChanged([in] EventRegistrationToken token);
+ [eventadd] HRESULT IsInputRedirectedChanged([in] Windows.Foundation.EventHandler *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
+#include
+
+#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
+
+#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(¬ify->refcount);
-
- if (!refcount)
- free(notify);
-
- return refcount;
+ return InterlockedDecrement(¬ify->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 = ¬ify_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 *)¬ify->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(¬ify->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 = ¬ify_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 *)¬ify->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(¬ify->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 = ¬ify_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(¬ify->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(¬ify->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 = ¬ify_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(¬ify->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(¬ify->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(¬ify->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 = ¬ify_impl.IMFMediaEngineNotify_iface;
IMFMediaEngine *media_engine;
double rate;
HRESULT hr;
- notify = create_callback();
-
- media_engine = create_media_engine(¬ify->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(¬ify->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 = ¬ify_impl.IMFMediaEngineNotify_iface;
IMFMediaEngine *media_engine;
HRESULT hr;
BOOL ret;
- notify = create_callback();
-
- media_engine = create_media_engine(¬ify->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(¬ify->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 = ¬ify_impl.IMFMediaEngineNotify_iface;
IMFMediaEngine *media_engine;
IMFMediaError *eo, *eo2;
unsigned int code;
HRESULT hr;
- notify = create_callback();
-
- media_engine = create_media_engine(¬ify->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(¬ify->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(¬ify->IMFMediaEngineNotify_iface);
- if (!media_engine)
- {
- win_skip("IMFMediaEngineEx is not supported.\n");
- IMFMediaEngineNotify_Release(¬ify->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(¬ify->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(¬ify->IMFMediaEngineNotify_iface);
- if (!media_engine)
- {
- IMFMediaEngineNotify_Release(¬ify->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(¬ify->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
-
#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
+#include
+#include
+#include
+#include
+#include
+
+#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, ¤t_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;
+ }
+ else if (IsEqualIID(riid, &IID_IMFRateControl))
+ {
+ *obj = &source->IMFRateControl_iface;
+ }
+ }
+ else
+ FIXME("Unsupported service %s.\n", debugstr_guid(service));
+
+ if (*obj)
+ IUnknown_AddRef((IUnknown *)*obj);
+
+ return *obj ? S_OK : E_NOINTERFACE;
+}
+
+static const IMFGetServiceVtbl media_source_get_service_vtbl =
+{
+ media_source_get_service_QueryInterface,
+ media_source_get_service_AddRef,
+ media_source_get_service_Release,
+ media_source_get_service_GetService,
+};
+
+static HRESULT WINAPI media_source_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
+{
+ struct media_source *source = impl_from_IMFRateSupport(iface);
+ return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
+}
+
+static ULONG WINAPI media_source_rate_support_AddRef(IMFRateSupport *iface)
+{
+ struct media_source *source = impl_from_IMFRateSupport(iface);
+ return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
+}
+
+static ULONG WINAPI media_source_rate_support_Release(IMFRateSupport *iface)
+{
+ struct media_source *source = impl_from_IMFRateSupport(iface);
+ return IMFMediaSource_Release(&source->IMFMediaSource_iface);
+}
+
+static HRESULT WINAPI media_source_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
+{
+ TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
+
+ *rate = 0.0f;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI media_source_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
+{
+ TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
+
+ *rate = direction == MFRATE_FORWARD ? 1e6f : -1e6f;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI media_source_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
+ float *nearest_rate)
+{
+ TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_rate);
+
+ if (nearest_rate)
+ *nearest_rate = rate;
+
+ return rate >= -1e6f && rate <= 1e6f ? S_OK : MF_E_UNSUPPORTED_RATE;
+}
+
+static const IMFRateSupportVtbl media_source_rate_support_vtbl =
+{
+ media_source_rate_support_QueryInterface,
+ media_source_rate_support_AddRef,
+ media_source_rate_support_Release,
+ media_source_rate_support_GetSlowestRate,
+ media_source_rate_support_GetFastestRate,
+ media_source_rate_support_IsRateSupported,
+};
+
+static HRESULT WINAPI media_source_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
+{
+ struct media_source *source = impl_from_IMFRateControl(iface);
+ return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
+}
+
+static ULONG WINAPI media_source_rate_control_AddRef(IMFRateControl *iface)
+{
+ struct media_source *source = impl_from_IMFRateControl(iface);
+ return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
+}
+
+static ULONG WINAPI media_source_rate_control_Release(IMFRateControl *iface)
+{
+ struct media_source *source = impl_from_IMFRateControl(iface);
+ return IMFMediaSource_Release(&source->IMFMediaSource_iface);
+}
+
+static HRESULT WINAPI media_source_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
+{
+ FIXME("%p, %d, %f.\n", iface, thin, rate);
+
+ if (rate < 0.0f)
+ return MF_E_REVERSE_UNSUPPORTED;
+
+ if (thin)
+ return MF_E_THINNING_UNSUPPORTED;
+
+ if (rate != 1.0f)
+ return MF_E_UNSUPPORTED_RATE;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI media_source_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
+{
+ TRACE("%p, %p, %p.\n", iface, thin, rate);
+
+ if (thin)
+ *thin = FALSE;
+
+ *rate = 1.0f;
+
+ return S_OK;
+}
+
+static const IMFRateControlVtbl media_source_rate_control_vtbl =
+{
+ media_source_rate_control_QueryInterface,
+ media_source_rate_control_AddRef,
+ media_source_rate_control_Release,
+ media_source_rate_control_SetRate,
+ media_source_rate_control_GetRate,
+};
+
+static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
+
+ if (IsEqualIID(riid, &IID_IMFMediaSource) ||
+ IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = &source->IMFMediaSource_iface;
+ }
+ else if (IsEqualIID(riid, &IID_IMFGetService))
+ {
+ *out = &source->IMFGetService_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_source_AddRef(IMFMediaSource *iface)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+ ULONG ref = InterlockedIncrement(&source->ref);
+
+ TRACE("%p, refcount %u.\n", iface, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+ ULONG ref = InterlockedDecrement(&source->ref);
+
+ TRACE("%p, refcount %u.\n", iface, ref);
+
+ if (!ref)
+ {
+ IMFMediaSource_Shutdown(&source->IMFMediaSource_iface);
+ IMFMediaEventQueue_Release(source->event_queue);
+ free(source);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ TRACE("%p, %#x, %p.\n", iface, flags, event);
+
+ return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
+}
+
+static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ TRACE("%p, %p, %p.\n", iface, callback, state);
+
+ return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
+}
+
+static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ TRACE("%p, %p, %p.\n", iface, result, event);
+
+ return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event);
+}
+
+static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
+ HRESULT hr, const PROPVARIANT *value)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ TRACE("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
+
+ return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value);
+}
+
+static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ TRACE("%p, %p.\n", iface, characteristics);
+
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ *characteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ TRACE("%p, %p.\n", iface, descriptor);
+
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return IMFPresentationDescriptor_Clone(source->pres_desc, descriptor);
+}
+
+static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
+ const GUID *time_format, const PROPVARIANT *position)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+ struct source_async_command *command;
+ HRESULT hr;
+
+ TRACE("%p, %p, %p, %p.\n", iface, descriptor, time_format, position);
+
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ if (!(IsEqualIID(time_format, &GUID_NULL)))
+ return MF_E_UNSUPPORTED_TIME_FORMAT;
+
+ if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &command)))
+ {
+ command->u.start.descriptor = descriptor;
+ command->u.start.format = *time_format;
+ PropVariantCopy(&command->u.start.position, position);
+
+ hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+ struct source_async_command *command;
+ HRESULT hr;
+
+ TRACE("%p.\n", iface);
+
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &command)))
+ hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
+
+ return hr;
+}
+
+static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+ struct source_async_command *command;
+ HRESULT hr;
+
+ TRACE("%p.\n", iface);
+
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ if (source->state != SOURCE_RUNNING)
+ return MF_E_INVALID_STATE_TRANSITION;
+
+ if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &command)))
+ hr = MFPutWorkItem(source->async_commands_queue,
+ &source->async_commands_callback, &command->IUnknown_iface);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+ unsigned int i;
+
+ TRACE("%p.\n", iface);
+
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ source->state = SOURCE_SHUTDOWN;
+
+ wg_parser_disconnect(source->wg_parser);
+
+ source->read_thread_shutdown = true;
+ WaitForSingleObject(source->read_thread, INFINITE);
+ CloseHandle(source->read_thread);
+
+ IMFPresentationDescriptor_Release(source->pres_desc);
+ IMFMediaEventQueue_Shutdown(source->event_queue);
+ IMFByteStream_Release(source->byte_stream);
+
+ for (i = 0; i < source->stream_count; i++)
+ {
+ struct media_stream *stream = source->streams[i];
+
+ stream->state = STREAM_SHUTDOWN;
+
+ IMFMediaEventQueue_Shutdown(stream->event_queue);
+ IMFStreamDescriptor_Release(stream->descriptor);
+ IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface);
+
+ IMFMediaStream_Release(&stream->IMFMediaStream_iface);
+ }
+
+ wg_parser_destroy(source->wg_parser);
+
+ free(source->streams);
+
+ MFUnlockWorkQueue(source->async_commands_queue);
+
+ return S_OK;
+}
+
+static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
+{
+ media_source_QueryInterface,
+ media_source_AddRef,
+ media_source_Release,
+ media_source_GetEvent,
+ media_source_BeginGetEvent,
+ media_source_EndGetEvent,
+ media_source_QueueEvent,
+ media_source_GetCharacteristics,
+ media_source_CreatePresentationDescriptor,
+ media_source_Start,
+ media_source_Stop,
+ media_source_Pause,
+ media_source_Shutdown,
+};
+
+static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source)
+{
+ BOOL video_selected = FALSE, audio_selected = FALSE;
+ IMFStreamDescriptor **descriptors = NULL;
+ unsigned int stream_count = UINT_MAX;
+ struct media_source *object;
+ UINT64 total_pres_time = 0;
+ struct wg_parser *parser;
+ DWORD bytestream_caps;
+ uint64_t file_size;
+ unsigned int i;
+ HRESULT hr;
+
+ if (FAILED(hr = IMFByteStream_GetCapabilities(bytestream, &bytestream_caps)))
+ return hr;
+
+ if (!(bytestream_caps & MFBYTESTREAM_IS_SEEKABLE))
+ {
+ FIXME("Non-seekable bytestreams not supported.\n");
+ return MF_E_BYTESTREAM_NOT_SEEKABLE;
+ }
+
+ if (FAILED(hr = IMFByteStream_GetLength(bytestream, &file_size)))
+ {
+ FIXME("Failed to get byte stream length, hr %#x.\n", hr);
+ return hr;
+ }
+
+ if (!(object = calloc(1, sizeof(*object))))
+ return E_OUTOFMEMORY;
+
+ object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
+ object->IMFGetService_iface.lpVtbl = &media_source_get_service_vtbl;
+ object->IMFRateSupport_iface.lpVtbl = &media_source_rate_support_vtbl;
+ object->IMFRateControl_iface.lpVtbl = &media_source_rate_control_vtbl;
+ object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl;
+ object->ref = 1;
+ object->byte_stream = bytestream;
+ IMFByteStream_AddRef(bytestream);
+
+ if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
+ goto fail;
+
+ if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue)))
+ goto fail;
+
+ /* In Media Foundation, sources may read from any media source stream
+ * without fear of blocking due to buffering limits on another. Trailmakers,
+ * a Unity3D Engine game, only reads one sample from the audio stream (and
+ * never deselects it). Remove buffering limits from decodebin in order to
+ * account for this. Note that this does leak memory, but the same memory
+ * leak occurs with native. */
+ if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, true)))
+ {
+ hr = E_OUTOFMEMORY;
+ goto fail;
+ }
+ object->wg_parser = parser;
+
+ object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL);
+
+ object->state = SOURCE_OPENING;
+
+ if (FAILED(hr = wg_parser_connect(parser, file_size)))
+ goto fail;
+
+ stream_count = wg_parser_get_stream_count(parser);
+
+ if (!(object->streams = calloc(stream_count, sizeof(*object->streams))))
+ {
+ hr = E_OUTOFMEMORY;
+ goto fail;
+ }
+
+ for (i = 0; i < stream_count; ++i)
+ {
+ if (FAILED(hr = new_media_stream(object, wg_parser_get_stream(parser, i), i, &object->streams[i])))
+ goto fail;
+
+ if (FAILED(hr = media_stream_init_desc(object->streams[i])))
+ {
+ ERR("Failed to finish initialization of media stream %p, hr %x.\n", object->streams[i], hr);
+ IMFMediaSource_Release(&object->streams[i]->parent_source->IMFMediaSource_iface);
+ IMFMediaEventQueue_Release(object->streams[i]->event_queue);
+ free(object->streams[i]);
+ goto fail;
+ }
+
+ object->stream_count++;
+ }
+
+ /* init presentation descriptor */
+
+ descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *));
+ for (i = 0; i < object->stream_count; i++)
+ {
+ IMFStreamDescriptor **descriptor = &descriptors[object->stream_count - 1 - i];
+ char language[128];
+ DWORD language_len;
+ WCHAR *languageW;
+
+ IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, descriptor);
+
+ if (wg_parser_stream_get_language(object->streams[i]->wg_stream, language, sizeof(language)))
+ {
+ if ((language_len = MultiByteToWideChar(CP_UTF8, 0, language, -1, NULL, 0)))
+ {
+ languageW = malloc(language_len * sizeof(WCHAR));
+ if (MultiByteToWideChar(CP_UTF8, 0, language, -1, languageW, language_len))
+ {
+ IMFStreamDescriptor_SetString(*descriptor, &MF_SD_LANGUAGE, languageW);
+ }
+ free(languageW);
+ }
+ }
+ }
+
+ if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc)))
+ goto fail;
+
+ /* Select one of each major type. */
+ for (i = 0; i < object->stream_count; i++)
+ {
+ IMFMediaTypeHandler *handler;
+ GUID major_type;
+ BOOL select_stream = FALSE;
+
+ IMFStreamDescriptor_GetMediaTypeHandler(descriptors[i], &handler);
+ IMFMediaTypeHandler_GetMajorType(handler, &major_type);
+ if (IsEqualGUID(&major_type, &MFMediaType_Video) && !video_selected)
+ {
+ select_stream = TRUE;
+ video_selected = TRUE;
+ }
+ if (IsEqualGUID(&major_type, &MFMediaType_Audio) && !audio_selected)
+ {
+ select_stream = TRUE;
+ audio_selected = TRUE;
+ }
+ if (select_stream)
+ IMFPresentationDescriptor_SelectStream(object->pres_desc, i);
+ IMFMediaTypeHandler_Release(handler);
+ IMFStreamDescriptor_Release(descriptors[i]);
+ }
+ free(descriptors);
+ descriptors = NULL;
+
+ for (i = 0; i < object->stream_count; i++)
+ total_pres_time = max(total_pres_time,
+ wg_parser_stream_get_duration(object->streams[i]->wg_stream));
+
+ if (object->stream_count)
+ IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time);
+
+ object->state = SOURCE_STOPPED;
+
+ *out_media_source = object;
+ return S_OK;
+
+ fail:
+ WARN("Failed to construct MFMediaSource, hr %#x.\n", hr);
+
+ if (descriptors)
+ {
+ for (i = 0; i < object->stream_count; i++)
+ IMFStreamDescriptor_Release(descriptors[i]);
+ free(descriptors);
+ }
+ for (i = 0; i < object->stream_count; i++)
+ {
+ struct media_stream *stream = object->streams[i];
+
+ IMFMediaEventQueue_Release(stream->event_queue);
+ IMFStreamDescriptor_Release(stream->descriptor);
+ IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface);
+
+ free(stream);
+ }
+ free(object->streams);
+ if (stream_count != UINT_MAX)
+ wg_parser_disconnect(object->wg_parser);
+ if (object->read_thread)
+ {
+ object->read_thread_shutdown = true;
+ WaitForSingleObject(object->read_thread, INFINITE);
+ CloseHandle(object->read_thread);
+ }
+ if (object->wg_parser)
+ wg_parser_destroy(object->wg_parser);
+ if (object->async_commands_queue)
+ MFUnlockWorkQueue(object->async_commands_queue);
+ if (object->event_queue)
+ IMFMediaEventQueue_Release(object->event_queue);
+ IMFByteStream_Release(object->byte_stream);
+ free(object);
+ return hr;
+}
+
+struct winegstreamer_stream_handler_result
+{
+ struct list entry;
+ IMFAsyncResult *result;
+ MF_OBJECT_TYPE obj_type;
+ IUnknown *object;
+};
+
+struct winegstreamer_stream_handler
+{
+ IMFByteStreamHandler IMFByteStreamHandler_iface;
+ IMFAsyncCallback IMFAsyncCallback_iface;
+ LONG refcount;
+ struct list results;
+ CRITICAL_SECTION cs;
+};
+
+static struct winegstreamer_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface)
+{
+ return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFByteStreamHandler_iface);
+}
+
+static struct winegstreamer_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
+{
+ return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFAsyncCallback_iface);
+}
+
+static HRESULT WINAPI winegstreamer_stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFByteStreamHandler) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IMFByteStreamHandler_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI winegstreamer_stream_handler_AddRef(IMFByteStreamHandler *iface)
+{
+ struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
+ ULONG refcount = InterlockedIncrement(&handler->refcount);
+
+ TRACE("%p, refcount %u.\n", handler, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI winegstreamer_stream_handler_Release(IMFByteStreamHandler *iface)
+{
+ struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
+ ULONG refcount = InterlockedDecrement(&handler->refcount);
+ struct winegstreamer_stream_handler_result *result, *next;
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct winegstreamer_stream_handler_result, entry)
+ {
+ list_remove(&result->entry);
+ IMFAsyncResult_Release(result->result);
+ if (result->object)
+ IUnknown_Release(result->object);
+ free(result);
+ }
+ DeleteCriticalSection(&handler->cs);
+ free(handler);
+ }
+
+ return refcount;
+}
+
+struct create_object_context
+{
+ IUnknown IUnknown_iface;
+ LONG refcount;
+
+ IPropertyStore *props;
+ IMFByteStream *stream;
+ WCHAR *url;
+ DWORD flags;
+};
+
+static struct create_object_context *impl_from_IUnknown(IUnknown *iface)
+{
+ return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface);
+}
+
+static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IUnknown_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI create_object_context_AddRef(IUnknown *iface)
+{
+ struct create_object_context *context = impl_from_IUnknown(iface);
+ ULONG refcount = InterlockedIncrement(&context->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI create_object_context_Release(IUnknown *iface)
+{
+ struct create_object_context *context = impl_from_IUnknown(iface);
+ ULONG refcount = InterlockedDecrement(&context->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ if (context->props)
+ IPropertyStore_Release(context->props);
+ if (context->stream)
+ IMFByteStream_Release(context->stream);
+ free(context->url);
+ free(context);
+ }
+
+ return refcount;
+}
+
+static const IUnknownVtbl create_object_context_vtbl =
+{
+ create_object_context_QueryInterface,
+ create_object_context_AddRef,
+ create_object_context_Release,
+};
+
+static HRESULT WINAPI winegstreamer_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags,
+ IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
+{
+ struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
+ struct create_object_context *context;
+ IMFAsyncResult *caller, *item;
+ HRESULT hr;
+
+ TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
+
+ if (cancel_cookie)
+ *cancel_cookie = NULL;
+
+ if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
+ return hr;
+
+ if (!(context = calloc(1, sizeof(*context))))
+ {
+ IMFAsyncResult_Release(caller);
+ return E_OUTOFMEMORY;
+ }
+
+ context->IUnknown_iface.lpVtbl = &create_object_context_vtbl;
+ context->refcount = 1;
+ context->props = props;
+ if (context->props)
+ IPropertyStore_AddRef(context->props);
+ context->flags = flags;
+ context->stream = stream;
+ if (context->stream)
+ IMFByteStream_AddRef(context->stream);
+ if (url)
+ context->url = wcsdup(url);
+ if (!context->stream)
+ {
+ IMFAsyncResult_Release(caller);
+ IUnknown_Release(&context->IUnknown_iface);
+ return E_OUTOFMEMORY;
+ }
+
+ hr = MFCreateAsyncResult(&context->IUnknown_iface, &this->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
+ IUnknown_Release(&context->IUnknown_iface);
+ if (SUCCEEDED(hr))
+ {
+ if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item)))
+ {
+ if (cancel_cookie)
+ {
+ *cancel_cookie = (IUnknown *)caller;
+ IUnknown_AddRef(*cancel_cookie);
+ }
+ }
+
+ IMFAsyncResult_Release(item);
+ }
+ IMFAsyncResult_Release(caller);
+
+ return hr;
+}
+
+static HRESULT WINAPI winegstreamer_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result,
+ MF_OBJECT_TYPE *obj_type, IUnknown **object)
+{
+ struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
+ struct winegstreamer_stream_handler_result *found = NULL, *cur;
+ HRESULT hr;
+
+ TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object);
+
+ EnterCriticalSection(&this->cs);
+
+ LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry)
+ {
+ if (result == cur->result)
+ {
+ list_remove(&cur->entry);
+ found = cur;
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&this->cs);
+
+ if (found)
+ {
+ *obj_type = found->obj_type;
+ *object = found->object;
+ hr = IMFAsyncResult_GetStatus(found->result);
+ IMFAsyncResult_Release(found->result);
+ free(found);
+ }
+ else
+ {
+ *obj_type = MF_OBJECT_INVALID;
+ *object = NULL;
+ hr = MF_E_UNEXPECTED;
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI winegstreamer_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie)
+{
+ struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
+ struct winegstreamer_stream_handler_result *found = NULL, *cur;
+
+ TRACE("%p, %p.\n", iface, cancel_cookie);
+
+ EnterCriticalSection(&this->cs);
+
+ LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry)
+ {
+ if (cancel_cookie == (IUnknown *)cur->result)
+ {
+ list_remove(&cur->entry);
+ found = cur;
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&this->cs);
+
+ if (found)
+ {
+ IMFAsyncResult_Release(found->result);
+ if (found->object)
+ IUnknown_Release(found->object);
+ free(found);
+ }
+
+ return found ? S_OK : MF_E_UNEXPECTED;
+}
+
+static HRESULT WINAPI winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes)
+{
+ FIXME("stub (%p %p)\n", iface, bytes);
+ return E_NOTIMPL;
+}
+
+static const IMFByteStreamHandlerVtbl winegstreamer_stream_handler_vtbl =
+{
+ winegstreamer_stream_handler_QueryInterface,
+ winegstreamer_stream_handler_AddRef,
+ winegstreamer_stream_handler_Release,
+ winegstreamer_stream_handler_BeginCreateObject,
+ winegstreamer_stream_handler_EndCreateObject,
+ winegstreamer_stream_handler_CancelObjectCreation,
+ winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution,
+};
+
+static HRESULT WINAPI winegstreamer_stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **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 ULONG WINAPI winegstreamer_stream_handler_callback_AddRef(IMFAsyncCallback *iface)
+{
+ struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
+ return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
+}
+
+static ULONG WINAPI winegstreamer_stream_handler_callback_Release(IMFAsyncCallback *iface)
+{
+ struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
+ return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
+}
+
+static HRESULT WINAPI winegstreamer_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler *This, WCHAR *url, IMFByteStream *stream, DWORD flags,
+ IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type)
+{
+ TRACE("%p, %s, %p, %u, %p, %p, %p.\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type);
+
+ if (flags & MF_RESOLUTION_MEDIASOURCE)
+ {
+ HRESULT hr;
+ struct media_source *new_source;
+
+ if (FAILED(hr = media_source_constructor(stream, &new_source)))
+ return hr;
+
+ TRACE("->(%p)\n", new_source);
+
+ *out_object = (IUnknown*)&new_source->IMFMediaSource_iface;
+ *out_obj_type = MF_OBJECT_MEDIASOURCE;
+
+ return S_OK;
+ }
+ else
+ {
+ FIXME("flags = %08x\n", flags);
+ return E_NOTIMPL;
+ }
+}
+
+static HRESULT WINAPI winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+ struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
+ struct winegstreamer_stream_handler_result *handler_result;
+ MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID;
+ IUnknown *object = NULL, *context_object;
+ struct create_object_context *context;
+ IMFAsyncResult *caller;
+ HRESULT hr;
+
+ caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
+
+ if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object)))
+ {
+ WARN("Expected context set for callee result.\n");
+ return hr;
+ }
+
+ context = impl_from_IUnknown(context_object);
+
+ hr = winegstreamer_stream_handler_create_object(handler, context->url, context->stream, context->flags, context->props, &object, &obj_type);
+
+ if ((handler_result = malloc(sizeof(*handler_result))))
+ {
+ handler_result->result = caller;
+ IMFAsyncResult_AddRef(handler_result->result);
+ handler_result->obj_type = obj_type;
+ handler_result->object = object;
+
+ EnterCriticalSection(&handler->cs);
+ list_add_tail(&handler->results, &handler_result->entry);
+ LeaveCriticalSection(&handler->cs);
+ }
+ else
+ {
+ if (object)
+ IUnknown_Release(object);
+ hr = E_OUTOFMEMORY;
+ }
+
+ IUnknown_Release(&context->IUnknown_iface);
+
+ IMFAsyncResult_SetStatus(caller, hr);
+ MFInvokeCallback(caller);
+
+ return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl winegstreamer_stream_handler_callback_vtbl =
+{
+ winegstreamer_stream_handler_callback_QueryInterface,
+ winegstreamer_stream_handler_callback_AddRef,
+ winegstreamer_stream_handler_callback_Release,
+ winegstreamer_stream_handler_callback_GetParameters,
+ winegstreamer_stream_handler_callback_Invoke,
+};
+
+HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj)
+{
+ struct winegstreamer_stream_handler *this;
+ HRESULT hr;
+
+ TRACE("%s, %p.\n", debugstr_guid(riid), obj);
+
+ if (!(this = calloc(1, sizeof(*this))))
+ return E_OUTOFMEMORY;
+
+ list_init(&this->results);
+ InitializeCriticalSection(&this->cs);
+
+ this->IMFByteStreamHandler_iface.lpVtbl = &winegstreamer_stream_handler_vtbl;
+ this->IMFAsyncCallback_iface.lpVtbl = &winegstreamer_stream_handler_callback_vtbl;
+ this->refcount = 1;
+
+ hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj);
+ IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface);
+
+ return hr;
+}
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c
index b36a44d1e1c..4f24ccbd237 100644
--- wine/dlls/mfplat/mediatype.c
+++ wine/dlls/mfplat/mediatype.c
@@ -25,6 +25,8 @@
#include "ks.h"
#include "ksmedia.h"
+#include "wine/debug.h"
+
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
DEFINE_MEDIATYPE_GUID(MFVideoFormat_IMC1, MAKEFOURCC('I','M','C','1'));
@@ -138,7 +140,7 @@ static ULONG WINAPI mediatype_AddRef(IMFMediaType *iface)
struct media_type *media_type = impl_from_IMFMediaType(iface);
ULONG refcount = InterlockedIncrement(&media_type->attributes.ref);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -148,7 +150,7 @@ static ULONG WINAPI mediatype_Release(IMFMediaType *iface)
struct media_type *media_type = impl_from_IMFMediaType(iface);
ULONG refcount = InterlockedDecrement(&media_type->attributes.ref);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
{
@@ -976,9 +978,8 @@ static const MFVIDEOFORMAT * WINAPI video_mediatype_GetVideoFormat(IMFVideoMedia
TRACE("%p.\n", iface);
CoTaskMemFree(media_type->video_format);
- media_type->video_format = NULL;
if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(&media_type->IMFMediaType_iface, &media_type->video_format, &size)))
- WARN("Failed to create format description, hr %#lx.\n", hr);
+ WARN("Failed to create format description, hr %#x.\n", hr);
return media_type->video_format;
}
@@ -986,7 +987,7 @@ static const MFVIDEOFORMAT * WINAPI video_mediatype_GetVideoFormat(IMFVideoMedia
static HRESULT WINAPI video_mediatype_GetVideoRepresentation(IMFVideoMediaType *iface, GUID representation,
void **data, LONG stride)
{
- FIXME("%p, %s, %p, %ld.\n", iface, debugstr_guid(&representation), data, stride);
+ FIXME("%p, %s, %p, %d.\n", iface, debugstr_guid(&representation), data, stride);
return E_NOTIMPL;
}
@@ -1377,11 +1378,10 @@ static const WAVEFORMATEX * WINAPI audio_mediatype_GetAudioFormat(IMFAudioMediaT
TRACE("%p.\n", iface);
CoTaskMemFree(media_type->audio_format);
- media_type->audio_format = NULL;
if (FAILED(hr = MFCreateWaveFormatExFromMFMediaType(&media_type->IMFMediaType_iface, &media_type->audio_format,
&size, MFWaveFormatExConvertFlag_Normal)))
{
- WARN("Failed to create wave format description, hr %#lx.\n", hr);
+ WARN("Failed to create wave format description, hr %#x.\n", hr);
}
return media_type->audio_format;
@@ -1498,7 +1498,7 @@ static ULONG WINAPI stream_descriptor_AddRef(IMFStreamDescriptor *iface)
struct stream_desc *stream_desc = impl_from_IMFStreamDescriptor(iface);
ULONG refcount = InterlockedIncrement(&stream_desc->attributes.ref);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -1509,7 +1509,7 @@ static ULONG WINAPI stream_descriptor_Release(IMFStreamDescriptor *iface)
ULONG refcount = InterlockedDecrement(&stream_desc->attributes.ref);
unsigned int i;
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
{
@@ -1955,7 +1955,7 @@ static HRESULT WINAPI mediatype_handler_GetMediaTypeByIndex(IMFMediaTypeHandler
{
struct stream_desc *stream_desc = impl_from_IMFMediaTypeHandler(iface);
- TRACE("%p, %lu, %p.\n", iface, index, type);
+ TRACE("%p, %u, %p.\n", iface, index, type);
if (index >= stream_desc->media_types_count)
return MF_E_NO_MORE_TYPES;
@@ -2046,7 +2046,7 @@ HRESULT WINAPI MFCreateStreamDescriptor(DWORD identifier, DWORD count,
unsigned int i;
HRESULT hr;
- TRACE("%ld, %ld, %p, %p.\n", identifier, count, types, descriptor);
+ TRACE("%d, %d, %p, %p.\n", identifier, count, types, descriptor);
if (!count)
return E_INVALIDARG;
@@ -2104,7 +2104,7 @@ static ULONG WINAPI presentation_descriptor_AddRef(IMFPresentationDescriptor *if
struct presentation_desc *presentation_desc = impl_from_IMFPresentationDescriptor(iface);
ULONG refcount = InterlockedIncrement(&presentation_desc->attributes.ref);
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
@@ -2115,7 +2115,7 @@ static ULONG WINAPI presentation_descriptor_Release(IMFPresentationDescriptor *i
ULONG refcount = InterlockedDecrement(&presentation_desc->attributes.ref);
unsigned int i;
- TRACE("%p, refcount %lu.\n", iface, refcount);
+ TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
{
@@ -2433,7 +2433,7 @@ static HRESULT WINAPI presentation_descriptor_GetStreamDescriptorByIndex(IMFPres
{
struct presentation_desc *presentation_desc = impl_from_IMFPresentationDescriptor(iface);
- TRACE("%p, %lu, %p, %p.\n", iface, index, selected, descriptor);
+ TRACE("%p, %u, %p, %p.\n", iface, index, selected, descriptor);
if (index >= presentation_desc->count)
return E_INVALIDARG;
@@ -2452,7 +2452,7 @@ static HRESULT WINAPI presentation_descriptor_SelectStream(IMFPresentationDescri
{
struct presentation_desc *presentation_desc = impl_from_IMFPresentationDescriptor(iface);
- TRACE("%p, %lu.\n", iface, index);
+ TRACE("%p, %u.\n", iface, index);
if (index >= presentation_desc->count)
return E_INVALIDARG;
@@ -2468,7 +2468,7 @@ static HRESULT WINAPI presentation_descriptor_DeselectStream(IMFPresentationDesc
{
struct presentation_desc *presentation_desc = impl_from_IMFPresentationDescriptor(iface);
- TRACE("%p, %lu.\n", iface, index);
+ TRACE("%p, %u.\n", iface, index);
if (index >= presentation_desc->count)
return E_INVALIDARG;
@@ -2580,7 +2580,7 @@ HRESULT WINAPI MFCreatePresentationDescriptor(DWORD count, IMFStreamDescriptor *
unsigned int i;
HRESULT hr;
- TRACE("%lu, %p, %p.\n", count, descriptors, out);
+ TRACE("%u, %p, %p.\n", count, descriptors, out);
if (!count)
return E_INVALIDARG;
@@ -2685,7 +2685,7 @@ HRESULT WINAPI MFGetStrideForBitmapInfoHeader(DWORD fourcc, DWORD width, LONG *s
struct uncompressed_video_format *format;
GUID subtype;
- TRACE("%s, %lu, %p.\n", debugstr_fourcc(fourcc), width, stride);
+ TRACE("%s, %u, %p.\n", debugstr_fourcc(fourcc), width, stride);
memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
subtype.Data1 = fourcc;
@@ -2752,15 +2752,15 @@ HRESULT WINAPI MFGetPlaneSize(DWORD fourcc, DWORD width, DWORD height, DWORD *si
unsigned int stride;
GUID subtype;
- TRACE("%s, %lu, %lu, %p.\n", debugstr_fourcc(fourcc), width, height, size);
+ TRACE("%s, %u, %u, %p.\n", debugstr_fourcc(fourcc), width, height, size);
memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
subtype.Data1 = fourcc;
- if ((format = mf_get_video_format(&subtype)))
- stride = mf_get_stride_for_format(format, width);
- else
- stride = 0;
+ if (!(format = mf_get_video_format(&subtype)))
+ return MF_E_INVALIDMEDIATYPE;
+
+ stride = mf_get_stride_for_format(format, width);
switch (fourcc)
{
@@ -2926,10 +2926,8 @@ HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *mediatype, WAVE
if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_NUM_CHANNELS, &value)))
format->nChannels = value;
- if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &value)))
- format->nSamplesPerSec = value;
- if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &value)))
- format->nAvgBytesPerSec = value;
+ IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &format->nSamplesPerSec);
+ IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &format->nAvgBytesPerSec);
if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &value)))
format->nBlockAlign = value;
if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_BITS_PER_SAMPLE, &value)))
@@ -2941,8 +2939,7 @@ HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *mediatype, WAVE
if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &value)))
format_ext->Samples.wSamplesPerBlock = value;
- if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_CHANNEL_MASK, &value)))
- format_ext->dwChannelMask = value;
+ IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_CHANNEL_MASK, &format_ext->dwChannelMask);
memcpy(&format_ext->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM, sizeof(format_ext->SubFormat));
}
@@ -3088,8 +3085,8 @@ HRESULT WINAPI MFCreateAudioMediaType(const WAVEFORMATEX *format, IMFAudioMediaT
return S_OK;
}
-static void media_type_get_ratio(IMFMediaType *media_type, const GUID *attr, DWORD *numerator,
- DWORD *denominator)
+static void media_type_get_ratio(IMFMediaType *media_type, const GUID *attr, UINT32 *numerator,
+ UINT32 *denominator)
{
UINT64 value;
@@ -3105,7 +3102,7 @@ static void media_type_get_ratio(IMFMediaType *media_type, const GUID *attr, DWO
*/
HRESULT WINAPI MFCreateMFVideoFormatFromMFMediaType(IMFMediaType *media_type, MFVIDEOFORMAT **video_format, UINT32 *size)
{
- UINT32 flags, palette_size = 0, value;
+ UINT32 flags, palette_size = 0, avgrate;
MFVIDEOFORMAT *format;
INT32 stride;
GUID guid;
@@ -3165,12 +3162,11 @@ HRESULT WINAPI MFCreateMFVideoFormatFromMFMediaType(IMFMediaType *media_type, MF
if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, (UINT32 *)&stride)) && stride < 0)
format->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep;
- if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &value)))
- format->compressedInfo.AvgBitrate = value;
- if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &value)))
- format->compressedInfo.AvgBitErrorRate = value;
- if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_MAX_KEYFRAME_SPACING, &value)))
- format->compressedInfo.MaxKeyFrameSpacing = value;
+ if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BITRATE, &avgrate)))
+ format->compressedInfo.AvgBitrate = avgrate;
+ if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AVG_BIT_ERROR_RATE, &avgrate)))
+ format->compressedInfo.AvgBitErrorRate = avgrate;
+ IMFMediaType_GetUINT32(media_type, &MF_MT_MAX_KEYFRAME_SPACING, &format->compressedInfo.MaxKeyFrameSpacing);
/* Palette. */
if (palette_size)
@@ -3217,15 +3213,15 @@ HRESULT WINAPI MFConvertColorInfoToDXVA(DWORD *dxva_info, const MFVIDEOFORMAT *f
struct frame_rate
{
- UINT64 key;
- UINT64 value;
+ UINT64 rate;
+ UINT64 frame_time;
};
static int __cdecl frame_rate_compare(const void *a, const void *b)
{
- const UINT64 *key = a;
+ const UINT64 *rate = a;
const struct frame_rate *known_rate = b;
- return *key == known_rate->key ? 0 : ( *key < known_rate->key ? 1 : -1 );
+ return *rate == known_rate->rate ? 0 : ( *rate < known_rate->rate ? 1 : -1 );
}
/***********************************************************************
@@ -3254,7 +3250,7 @@ HRESULT WINAPI MFFrameRateToAverageTimePerFrame(UINT32 numerator, UINT32 denomin
if ((entry = bsearch(&rate, known_rates, ARRAY_SIZE(known_rates), sizeof(*known_rates),
frame_rate_compare)))
{
- *avgframetime = entry->value;
+ *avgframetime = entry->frame_time;
}
else
*avgframetime = numerator ? denominator * (UINT64)10000000 / numerator : 0;
@@ -3262,64 +3258,6 @@ HRESULT WINAPI MFFrameRateToAverageTimePerFrame(UINT32 numerator, UINT32 denomin
return S_OK;
}
-static unsigned int get_gcd(unsigned int a, unsigned int b)
-{
- unsigned int m;
-
- while (b)
- {
- m = a % b;
- a = b;
- b = m;
- }
-
- return a;
-}
-
-/***********************************************************************
- * MFAverageTimePerFrameToFrameRate (mfplat.@)
- */
-HRESULT WINAPI MFAverageTimePerFrameToFrameRate(UINT64 avgtime, UINT32 *numerator, UINT32 *denominator)
-{
- static const struct frame_rate known_rates[] =
- {
-#define KNOWN_RATE(ft,n,d) { ft, ((UINT64)n << 32) | d }
- KNOWN_RATE(417188, 24000, 1001),
- KNOWN_RATE(416667, 24, 1),
- KNOWN_RATE(400000, 25, 1),
- KNOWN_RATE(333667, 30000, 1001),
- KNOWN_RATE(333333, 30, 1),
- KNOWN_RATE(200000, 50, 1),
- KNOWN_RATE(166833, 60000, 1001),
- KNOWN_RATE(166667, 60, 1),
-#undef KNOWN_RATE
- };
- const struct frame_rate *entry;
- unsigned int gcd;
-
- TRACE("%s, %p, %p.\n", wine_dbgstr_longlong(avgtime), numerator, denominator);
-
- if ((entry = bsearch(&avgtime, known_rates, ARRAY_SIZE(known_rates), sizeof(*known_rates),
- frame_rate_compare)))
- {
- *numerator = entry->value >> 32;
- *denominator = entry->value;
- }
- else if (avgtime)
- {
- if (avgtime > 100000000) avgtime = 100000000;
- gcd = get_gcd(10000000, avgtime);
- *numerator = 10000000 / gcd;
- *denominator = avgtime / gcd;
- }
- else
- {
- *numerator = *denominator = 0;
- }
-
- return S_OK;
-}
-
/***********************************************************************
* MFMapDXGIFormatToDX9Format (mfplat.@)
*/
@@ -3513,7 +3451,7 @@ HRESULT WINAPI MFInitVideoFormat_RGB(MFVIDEOFORMAT *format, DWORD width, DWORD h
{
unsigned int transfer_function;
- TRACE("%p, %lu, %lu, %#lx.\n", format, width, height, d3dformat);
+ TRACE("%p, %u, %u, %#x.\n", format, width, height, d3dformat);
if (!format)
return E_INVALIDARG;
diff --git a/dlls/mfplat/mfplat.c b/dlls/mfplat/mfplat.c
new file mode 100644
index 00000000000..3ec45d7de4e
--- /dev/null
+++ wine/dlls/mfplat/mfplat.c
@@ -0,0 +1,1036 @@
+/*
+ * Copyright 2019 Nikolay Sivov for CodeWeavers
+ * 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 "ks.h"
+#include "ksmedia.h"
+#include "wmcodecdsp.h"
+#include "initguid.h"
+#include "mfapi.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166);
+
+struct video_processor
+{
+ IMFTransform IMFTransform_iface;
+ LONG refcount;
+ IMFAttributes *attributes;
+ IMFAttributes *output_attributes;
+};
+
+static struct video_processor *impl_video_processor_from_IMFTransform(IMFTransform *iface)
+{
+ return CONTAINING_RECORD(iface, struct video_processor, IMFTransform_iface);
+}
+
+static HRESULT WINAPI video_processor_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 video_processor_AddRef(IMFTransform *iface)
+{
+ struct video_processor *transform = impl_video_processor_from_IMFTransform(iface);
+ ULONG refcount = InterlockedIncrement(&transform->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI video_processor_Release(IMFTransform *iface)
+{
+ struct video_processor *transform = impl_video_processor_from_IMFTransform(iface);
+ ULONG refcount = InterlockedDecrement(&transform->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ if (transform->attributes)
+ IMFAttributes_Release(transform->attributes);
+ if (transform->output_attributes)
+ IMFAttributes_Release(transform->output_attributes);
+ free(transform);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI video_processor_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 video_processor_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
+{
+ TRACE("%p, %p, %p.\n", iface, inputs, outputs);
+
+ *inputs = *outputs = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI video_processor_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
+ DWORD output_size, DWORD *outputs)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
+{
+ struct video_processor *transform = impl_video_processor_from_IMFTransform(iface);
+
+ TRACE("%p, %p.\n", iface, attributes);
+
+ *attributes = transform->attributes;
+ IMFAttributes_AddRef(*attributes);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI video_processor_GetInputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_GetOutputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ struct video_processor *transform = impl_video_processor_from_IMFTransform(iface);
+
+ TRACE("%p, %u, %p.\n", iface, id, attributes);
+
+ *attributes = transform->output_attributes;
+ IMFAttributes_AddRef(*attributes);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI video_processor_DeleteInputStream(IMFTransform *iface, DWORD id)
+{
+ TRACE("%p, %u.\n", iface, id);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
+{
+ TRACE("%p, %u, %p.\n", iface, streams, ids);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ FIXME("%p, %u, %u, %p.\n", iface, id, index, type);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ FIXME("%p, %u, %u, %p.\n", iface, id, index, type);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ FIXME("%p, %u, %p.\n", iface, id, type);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ FIXME("%p, %u, %p.\n", iface, id, type);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
+{
+ FIXME("%p, %u, %p.\n", iface, id, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_GetOutputStatus(IMFTransform *iface, DWORD *flags)
+{
+ FIXME("%p, %p.\n", iface, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_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 video_processor_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
+{
+ TRACE("%p, %u, %p.\n", iface, id, event);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
+{
+ FIXME("%p, %u.\n", iface, message);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
+{
+ FIXME("%p, %u, %p, %#x.\n", iface, id, sample, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
+{
+ FIXME("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status);
+
+ return E_NOTIMPL;
+}
+
+static const IMFTransformVtbl video_processor_vtbl =
+{
+ video_processor_QueryInterface,
+ video_processor_AddRef,
+ video_processor_Release,
+ video_processor_GetStreamLimits,
+ video_processor_GetStreamCount,
+ video_processor_GetStreamIDs,
+ video_processor_GetInputStreamInfo,
+ video_processor_GetOutputStreamInfo,
+ video_processor_GetAttributes,
+ video_processor_GetInputStreamAttributes,
+ video_processor_GetOutputStreamAttributes,
+ video_processor_DeleteInputStream,
+ video_processor_AddInputStreams,
+ video_processor_GetInputAvailableType,
+ video_processor_GetOutputAvailableType,
+ video_processor_SetInputType,
+ video_processor_SetOutputType,
+ video_processor_GetInputCurrentType,
+ video_processor_GetOutputCurrentType,
+ video_processor_GetInputStatus,
+ video_processor_GetOutputStatus,
+ video_processor_SetOutputBounds,
+ video_processor_ProcessEvent,
+ video_processor_ProcessMessage,
+ video_processor_ProcessInput,
+ video_processor_ProcessOutput,
+};
+
+struct class_factory
+{
+ IClassFactory IClassFactory_iface;
+ LONG refcount;
+ HRESULT (*create_instance)(REFIID riid, void **obj);
+};
+
+static struct class_factory *impl_from_IClassFactory(IClassFactory *iface)
+{
+ return CONTAINING_RECORD(iface, struct class_factory, IClassFactory_iface);
+}
+
+static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualGUID(riid, &IID_IClassFactory) ||
+ IsEqualGUID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IClassFactory_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("%s is not supported.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
+{
+ struct class_factory *factory = impl_from_IClassFactory(iface);
+ return InterlockedIncrement(&factory->refcount);
+}
+
+static ULONG WINAPI class_factory_Release(IClassFactory *iface)
+{
+ struct class_factory *factory = impl_from_IClassFactory(iface);
+ ULONG refcount = InterlockedDecrement(&factory->refcount);
+
+ if (!refcount)
+ free(factory);
+
+ return refcount;
+}
+
+static HRESULT WINAPI class_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj)
+{
+ struct class_factory *factory = impl_from_IClassFactory(iface);
+
+ TRACE("%p, %p, %s, %p.\n", iface, outer, debugstr_guid(riid), obj);
+
+ if (outer)
+ {
+ *obj = NULL;
+ return CLASS_E_NOAGGREGATION;
+ }
+
+ return factory->create_instance(riid, obj);
+}
+
+static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL dolock)
+{
+ TRACE("%p, %d.\n", iface, dolock);
+ return S_OK;
+}
+
+static const IClassFactoryVtbl class_factory_vtbl =
+{
+ class_factory_QueryInterface,
+ class_factory_AddRef,
+ class_factory_Release,
+ class_factory_CreateInstance,
+ class_factory_LockServer,
+};
+
+static HRESULT video_processor_create(REFIID riid, void **ret)
+{
+ struct video_processor *object;
+ HRESULT hr;
+
+ if (!(object = calloc(1, sizeof(*object))))
+ return E_OUTOFMEMORY;
+
+ object->IMFTransform_iface.lpVtbl = &video_processor_vtbl;
+ object->refcount = 1;
+
+ if (FAILED(hr = MFCreateAttributes(&object->attributes, 0)))
+ goto failed;
+
+ if (FAILED(hr = MFCreateAttributes(&object->output_attributes, 0)))
+ goto failed;
+
+ *ret = &object->IMFTransform_iface;
+ return S_OK;
+
+failed:
+
+ IMFTransform_Release(&object->IMFTransform_iface);
+ return hr;
+}
+
+static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}};
+
+static const GUID CLSID_WINEAudioConverter = {0x6a170414,0xaad9,0x4693,{0xb8,0x06,0x3a,0x0c,0x47,0xc5,0x70,0xd6}};
+
+static const struct class_object
+{
+ const GUID *clsid;
+ HRESULT (*create_instance)(REFIID riid, void **obj);
+}
+class_objects[] =
+{
+ { &CLSID_VideoProcessorMFT, &video_processor_create },
+ { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create },
+ { &CLSID_WINEAudioConverter, &audio_converter_create },
+ { &CLSID_CColorConvertDMO, &color_converter_create },
+ { &CLSID_MSH264DecoderMFT, &h264_decoder_create },
+ { &CLSID_MSAACDecMFT, &aac_decoder_create },
+};
+
+HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
+{
+ struct class_factory *factory;
+ unsigned int i;
+ HRESULT hr;
+
+ for (i = 0; i < ARRAY_SIZE(class_objects); ++i)
+ {
+ if (IsEqualGUID(class_objects[i].clsid, rclsid))
+ {
+ if (!(factory = malloc(sizeof(*factory))))
+ return E_OUTOFMEMORY;
+
+ factory->IClassFactory_iface.lpVtbl = &class_factory_vtbl;
+ factory->refcount = 1;
+ factory->create_instance = class_objects[i].create_instance;
+
+ hr = IClassFactory_QueryInterface(&factory->IClassFactory_iface, riid, obj);
+ IClassFactory_Release(&factory->IClassFactory_iface);
+ return hr;
+ }
+ }
+
+ return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+static WCHAR audio_converterW[] = L"Audio Converter";
+static const GUID *audio_converter_supported_types[] =
+{
+ &MFAudioFormat_PCM,
+ &MFAudioFormat_Float,
+};
+
+static WCHAR wma_decoderW[] = L"WMAudio Decoder MFT";
+static const GUID *wma_decoder_input_types[] =
+{
+ &MEDIASUBTYPE_MSAUDIO1,
+ &MFAudioFormat_WMAudioV8,
+ &MFAudioFormat_WMAudioV9,
+ &MFAudioFormat_WMAudio_Lossless,
+};
+static const GUID *wma_decoder_output_types[] =
+{
+ &MFAudioFormat_PCM,
+ &MFAudioFormat_Float,
+};
+
+static WCHAR video_processorW[] = L"Video Processor MFT";
+static const GUID *video_processor_supported_types[] =
+{
+ &MFVideoFormat_IYUV,
+};
+
+static WCHAR color_converterW[] = L"Color Converter";
+static const GUID *color_converter_supported_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,
+};
+
+static WCHAR h264_decoderW[] = L"H.264 Decoder";
+static const GUID *h264_decoder_input_types[] =
+{
+ &MFVideoFormat_H264,
+};
+static const GUID *h264_decoder_output_types[] =
+{
+ &MFVideoFormat_NV12,
+ &MFVideoFormat_I420,
+ &MFVideoFormat_IYUV,
+ &MFVideoFormat_YUY2,
+ &MFVideoFormat_YV12,
+};
+
+static WCHAR aac_decoderW[] = L"AAC Decoder";
+static const GUID *aac_decoder_input_types[] =
+{
+ &MFAudioFormat_AAC,
+};
+static const GUID *aac_decoder_output_types[] =
+{
+ &MFAudioFormat_Float,
+ &MFAudioFormat_PCM,
+};
+
+static const struct mft
+{
+ const GUID *clsid;
+ const GUID *category;
+ LPWSTR name;
+ const UINT32 flags;
+ const GUID *major_type;
+ const UINT32 input_types_count;
+ const GUID **input_types;
+ const UINT32 output_types_count;
+ const GUID **output_types;
+}
+mfts[] =
+{
+ {
+ &CLSID_WINEAudioConverter,
+ &MFT_CATEGORY_AUDIO_EFFECT,
+ audio_converterW,
+ MFT_ENUM_FLAG_SYNCMFT,
+ &MFMediaType_Audio,
+ ARRAY_SIZE(audio_converter_supported_types),
+ audio_converter_supported_types,
+ ARRAY_SIZE(audio_converter_supported_types),
+ audio_converter_supported_types,
+ },
+ {
+ &CLSID_WMADecMediaObject,
+ &MFT_CATEGORY_AUDIO_DECODER,
+ wma_decoderW,
+ MFT_ENUM_FLAG_SYNCMFT,
+ &MFMediaType_Audio,
+ ARRAY_SIZE(wma_decoder_input_types),
+ wma_decoder_input_types,
+ ARRAY_SIZE(wma_decoder_output_types),
+ wma_decoder_output_types,
+ },
+ {
+ &CLSID_VideoProcessorMFT,
+ &MFT_CATEGORY_VIDEO_PROCESSOR,
+ video_processorW,
+ 0,
+ &MFMediaType_Video,
+ ARRAY_SIZE(video_processor_supported_types),
+ video_processor_supported_types,
+ ARRAY_SIZE(video_processor_supported_types),
+ video_processor_supported_types,
+ },
+ {
+ &CLSID_CColorConvertDMO,
+ &MFT_CATEGORY_VIDEO_EFFECT,
+ color_converterW,
+ MFT_ENUM_FLAG_SYNCMFT,
+ &MFMediaType_Video,
+ ARRAY_SIZE(color_converter_supported_types),
+ color_converter_supported_types,
+ ARRAY_SIZE(color_converter_supported_types),
+ color_converter_supported_types,
+ },
+ {
+ &CLSID_MSH264DecoderMFT,
+ &MFT_CATEGORY_VIDEO_DECODER,
+ h264_decoderW,
+ MFT_ENUM_FLAG_SYNCMFT,
+ &MFMediaType_Video,
+ ARRAY_SIZE(h264_decoder_input_types),
+ h264_decoder_input_types,
+ ARRAY_SIZE(h264_decoder_output_types),
+ h264_decoder_output_types,
+ },
+ {
+ &CLSID_MSAACDecMFT,
+ &MFT_CATEGORY_AUDIO_DECODER,
+ aac_decoderW,
+ MFT_ENUM_FLAG_SYNCMFT,
+ &MFMediaType_Audio,
+ ARRAY_SIZE(aac_decoder_input_types),
+ aac_decoder_input_types,
+ ARRAY_SIZE(aac_decoder_output_types),
+ aac_decoder_output_types,
+ },
+};
+
+HRESULT mfplat_DllRegisterServer(void)
+{
+ unsigned int i, j;
+ HRESULT hr;
+ MFT_REGISTER_TYPE_INFO input_types[15], output_types[15];
+
+ for (i = 0; i < ARRAY_SIZE(mfts); i++)
+ {
+ const struct mft *cur = &mfts[i];
+
+ for (j = 0; j < cur->input_types_count; j++)
+ {
+ input_types[j].guidMajorType = *(cur->major_type);
+ input_types[j].guidSubtype = *(cur->input_types[j]);
+ }
+ for (j = 0; j < cur->output_types_count; j++)
+ {
+ output_types[j].guidMajorType = *(cur->major_type);
+ output_types[j].guidSubtype = *(cur->output_types[j]);
+ }
+
+ hr = MFTRegister(*(cur->clsid), *(cur->category), cur->name, cur->flags, cur->input_types_count,
+ input_types, cur->output_types_count, output_types, NULL);
+
+ if (FAILED(hr))
+ {
+ FIXME("Failed to register MFT, hr %#x\n", hr);
+ return hr;
+ }
+ }
+ return S_OK;
+}
+
+static const struct
+{
+ const GUID *subtype;
+ enum wg_video_format format;
+}
+video_formats[] =
+{
+ {&MFVideoFormat_ARGB32, WG_VIDEO_FORMAT_BGRA},
+ {&MFVideoFormat_RGB32, WG_VIDEO_FORMAT_BGRx},
+ {&MFVideoFormat_RGB24, WG_VIDEO_FORMAT_BGR},
+ {&MFVideoFormat_RGB555, WG_VIDEO_FORMAT_RGB15},
+ {&MFVideoFormat_RGB565, WG_VIDEO_FORMAT_RGB16},
+ {&MFVideoFormat_AYUV, WG_VIDEO_FORMAT_AYUV},
+ {&MFVideoFormat_I420, WG_VIDEO_FORMAT_I420},
+ {&MFVideoFormat_IYUV, WG_VIDEO_FORMAT_I420},
+ {&MFVideoFormat_NV12, WG_VIDEO_FORMAT_NV12},
+ {&MFVideoFormat_UYVY, WG_VIDEO_FORMAT_UYVY},
+ {&MFVideoFormat_YUY2, WG_VIDEO_FORMAT_YUY2},
+ {&MFVideoFormat_YV12, WG_VIDEO_FORMAT_YV12},
+ {&MFVideoFormat_YVYU, WG_VIDEO_FORMAT_YVYU},
+};
+
+static const struct
+{
+ const GUID *subtype;
+ UINT32 depth;
+ enum wg_audio_format format;
+}
+audio_formats[] =
+{
+ {&MFAudioFormat_PCM, 8, WG_AUDIO_FORMAT_U8},
+ {&MFAudioFormat_PCM, 16, WG_AUDIO_FORMAT_S16LE},
+ {&MFAudioFormat_PCM, 24, WG_AUDIO_FORMAT_S24LE},
+ {&MFAudioFormat_PCM, 32, WG_AUDIO_FORMAT_S32LE},
+ {&MFAudioFormat_Float, 32, WG_AUDIO_FORMAT_F32LE},
+ {&MFAudioFormat_Float, 64, WG_AUDIO_FORMAT_F64LE},
+};
+
+static inline UINT64 make_uint64(UINT32 high, UINT32 low)
+{
+ return ((UINT64)high << 32) | low;
+}
+
+static IMFMediaType *mf_media_type_from_wg_format_audio(const struct wg_format *format)
+{
+ IMFMediaType *type;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(audio_formats); ++i)
+ {
+ if (format->u.audio.format == audio_formats[i].format)
+ {
+ if (FAILED(MFCreateMediaType(&type)))
+ return NULL;
+
+ IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+ IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, audio_formats[i].subtype);
+ IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, audio_formats[i].depth);
+ IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, format->u.audio.rate);
+ IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, format->u.audio.channels);
+ if (format->u.audio.channel_mask)
+ IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, format->u.audio.channel_mask);
+ IMFMediaType_SetUINT32(type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
+ IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, format->u.audio.channels * audio_formats[i].depth / 8);
+
+ return type;
+ }
+ }
+
+ return NULL;
+}
+
+static IMFMediaType *mf_media_type_from_wg_format_video(const struct wg_format *format)
+{
+ IMFMediaType *type;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(video_formats); ++i)
+ {
+ if (format->u.video.format == video_formats[i].format)
+ {
+ if (FAILED(MFCreateMediaType(&type)))
+ return NULL;
+
+ IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
+ IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, video_formats[i].subtype);
+ IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE,
+ make_uint64(format->u.video.width, format->u.video.height));
+ IMFMediaType_SetUINT64(type, &MF_MT_FRAME_RATE,
+ make_uint64(format->u.video.fps_n, format->u.video.fps_d));
+ IMFMediaType_SetUINT32(type, &MF_MT_COMPRESSED, FALSE);
+ IMFMediaType_SetUINT32(type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
+ IMFMediaType_SetUINT32(type, &MF_MT_VIDEO_ROTATION, MFVideoRotationFormat_0);
+
+ return type;
+ }
+ }
+
+ return NULL;
+}
+
+IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format)
+{
+ switch (format->major_type)
+ {
+ case WG_MAJOR_TYPE_UNKNOWN:
+ return NULL;
+
+ case WG_MAJOR_TYPE_AUDIO:
+ return mf_media_type_from_wg_format_audio(format);
+
+ case WG_MAJOR_TYPE_VIDEO:
+ return mf_media_type_from_wg_format_video(format);
+ }
+
+ assert(0);
+ return NULL;
+}
+
+static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_format *format)
+{
+ UINT32 rate, channels, channel_mask, depth;
+ unsigned int i;
+ GUID subtype;
+
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ {
+ FIXME("Subtype is not set.\n");
+ return;
+ }
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate)))
+ {
+ FIXME("Sample rate is not set.\n");
+ return;
+ }
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels)))
+ {
+ FIXME("Channel count is not set.\n");
+ return;
+ }
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &depth)))
+ {
+ FIXME("Depth is not set.\n");
+ return;
+ }
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, &channel_mask)))
+ {
+ if (channels == 1)
+ channel_mask = KSAUDIO_SPEAKER_MONO;
+ else if (channels == 2)
+ channel_mask = KSAUDIO_SPEAKER_STEREO;
+ else if IsEqualGUID(&subtype, &MFAudioFormat_AAC)
+ channel_mask = 0;
+ else
+ {
+ FIXME("Channel mask is not set.\n");
+ return;
+ }
+ }
+
+ format->major_type = WG_MAJOR_TYPE_AUDIO;
+ format->u.audio.channels = channels;
+ format->u.audio.channel_mask = channel_mask;
+ format->u.audio.rate = rate;
+
+ for (i = 0; i < ARRAY_SIZE(audio_formats); ++i)
+ {
+ if (IsEqualGUID(&subtype, audio_formats[i].subtype) && depth == audio_formats[i].depth)
+ {
+ format->u.audio.format = audio_formats[i].format;
+ return;
+ }
+ }
+ FIXME("Unrecognized audio subtype %s, depth %u.\n", debugstr_guid(&subtype), depth);
+}
+
+static void mf_media_type_to_wg_format_video(IMFMediaType *type, struct wg_format *format)
+{
+ UINT64 frame_rate, frame_size;
+ unsigned int i;
+ GUID subtype;
+
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ {
+ FIXME("Subtype is not set.\n");
+ return;
+ }
+ if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
+ {
+ FIXME("Frame size is not set.\n");
+ return;
+ }
+
+ format->major_type = WG_MAJOR_TYPE_VIDEO;
+ format->u.video.width = (UINT32)(frame_size >> 32);
+ format->u.video.height = (UINT32)frame_size;
+ format->u.video.fps_n = 1;
+ format->u.video.fps_d = 1;
+
+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate)
+ {
+ format->u.video.fps_n = (UINT32)(frame_rate >> 32);
+ format->u.video.fps_d = (UINT32)frame_rate;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(video_formats); ++i)
+ {
+ if (IsEqualGUID(&subtype, video_formats[i].subtype))
+ {
+ format->u.video.format = video_formats[i].format;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(video_formats))
+ FIXME("Unrecognized video subtype %s.\n", debugstr_guid(&subtype));
+}
+
+void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format)
+{
+ GUID major_type;
+
+ memset(format, 0, sizeof(*format));
+
+ if (FAILED(IMFMediaType_GetMajorType(type, &major_type)))
+ {
+ FIXME("Major type is not set.\n");
+ return;
+ }
+
+ if (IsEqualGUID(&major_type, &MFMediaType_Audio))
+ mf_media_type_to_wg_format_audio(type, format);
+ else if (IsEqualGUID(&major_type, &MFMediaType_Video))
+ mf_media_type_to_wg_format_video(type, format);
+ else
+ FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type));
+}
+
+static void mf_media_type_to_wg_encoded_format_xwma(IMFMediaType *type, struct wg_encoded_format *format,
+ enum wg_encoded_type encoded_type, UINT32 version)
+{
+ UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len;
+ BYTE codec_data[64];
+
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate)))
+ {
+ FIXME("Sample rate is not set.\n");
+ return;
+ }
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels)))
+ {
+ FIXME("Channel count is not set.\n");
+ return;
+ }
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second)))
+ {
+ FIXME("Bitrate is not set.\n");
+ return;
+ }
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_align)))
+ {
+ FIXME("Block alignment is not set.\n");
+ return;
+ }
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &depth)))
+ {
+ FIXME("Depth is not set.\n");
+ return;
+ }
+ if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, codec_data, sizeof(codec_data), &codec_data_len)))
+ {
+ FIXME("Codec data is not set.\n");
+ return;
+ }
+
+ format->encoded_type = encoded_type;
+ format->u.xwma.version = version;
+ format->u.xwma.bitrate = bytes_per_second * 8;
+ format->u.xwma.rate = rate;
+ format->u.xwma.depth = depth;
+ format->u.xwma.channels = channels;
+ format->u.xwma.block_align = block_align;
+ format->u.xwma.codec_data_len = codec_data_len;
+ memcpy(format->u.xwma.codec_data, codec_data, codec_data_len);
+}
+
+static void mf_media_type_to_wg_encoded_format_aac(IMFMediaType *type, struct wg_encoded_format *format)
+{
+ UINT32 codec_data_len, payload_type, profile_level_indication;
+ BYTE codec_data[64];
+
+ /* Audio specific config is stored at after HEAACWAVEINFO in MF_MT_USER_DATA
+ * https://docs.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-heaacwaveformat
+ */
+ struct
+ {
+ WORD payload_type;
+ WORD profile_level_indication;
+ WORD type;
+ WORD reserved1;
+ DWORD reserved2;
+ } *aac_info = (void *)codec_data;
+
+ if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, codec_data, sizeof(codec_data), &codec_data_len)))
+ {
+ FIXME("Codec data is not set.\n");
+ return;
+ }
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &payload_type)))
+ {
+ FIXME("AAC payload type is not set.\n");
+ payload_type = aac_info->payload_type;
+ }
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &profile_level_indication)))
+ {
+ FIXME("AAC provile level indication is not set.\n");
+ profile_level_indication = aac_info->profile_level_indication;
+ }
+
+ format->encoded_type = WG_ENCODED_TYPE_AAC;
+ format->u.aac.payload_type = payload_type;
+ format->u.aac.profile_level_indication = profile_level_indication;
+ format->u.aac.codec_data_len = 0;
+
+ if (codec_data_len > sizeof(*aac_info))
+ {
+ format->u.aac.codec_data_len = codec_data_len - sizeof(*aac_info);
+ memcpy(format->u.aac.codec_data, codec_data + sizeof(*aac_info), codec_data_len - sizeof(*aac_info));
+ }
+}
+
+static void mf_media_type_to_wg_encoded_format_h264(IMFMediaType *type, struct wg_encoded_format *format)
+{
+ UINT64 frame_rate, frame_size;
+ UINT32 profile, level;
+
+ format->encoded_type = WG_ENCODED_TYPE_H264;
+ format->u.h264.width = 0;
+ format->u.h264.height = 0;
+ format->u.h264.fps_n = 1;
+ format->u.h264.fps_d = 1;
+
+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
+ {
+ format->u.h264.width = (UINT32)(frame_size >> 32);
+ format->u.h264.height = (UINT32)frame_size;
+ }
+
+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate)
+ {
+ format->u.h264.fps_n = (UINT32)(frame_rate >> 32);
+ format->u.h264.fps_d = (UINT32)frame_rate;
+ }
+
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &profile)))
+ format->u.h264.profile = profile;
+
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &level)))
+ format->u.h264.level = level;
+}
+
+void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_format *format)
+{
+ GUID major_type, subtype;
+
+ memset(format, 0, sizeof(*format));
+
+ if (FAILED(IMFMediaType_GetMajorType(type, &major_type)))
+ {
+ FIXME("Major type is not set.\n");
+ return;
+ }
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ {
+ FIXME("Subtype is not set.\n");
+ return;
+ }
+
+ if (IsEqualGUID(&major_type, &MFMediaType_Audio))
+ {
+ if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1))
+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 1);
+ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8))
+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 2);
+ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9))
+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 3);
+ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless))
+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 4);
+ else if (IsEqualGUID(&subtype, &MFAudioFormat_XMAudio2))
+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_XMA, 2);
+ else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC))
+ mf_media_type_to_wg_encoded_format_aac(type, format);
+ else
+ FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype));
+ }
+ else if (IsEqualGUID(&major_type, &MFMediaType_Video))
+ {
+ if (IsEqualGUID(&subtype, &MFVideoFormat_H264))
+ mf_media_type_to_wg_encoded_format_h264(type, format);
+ else
+ FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype));
+ }
+ else
+ {
+ FIXME("Unimplemented major type %s.\n", debugstr_guid(&major_type));
+ }
+}
diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec
index 31c80f596c2..44d98a957e2 100644
--- wine/dlls/mfplat/mfplat.spec
+++ wine/dlls/mfplat/mfplat.spec
@@ -20,7 +20,7 @@
@ stdcall MFAllocateWorkQueue(ptr)
@ stdcall MFAllocateWorkQueueEx(long ptr) rtworkq.RtwqAllocateWorkQueue
@ stub MFAppendCollection
-@ stdcall MFAverageTimePerFrameToFrameRate(int64 ptr ptr)
+@ stub MFAverageTimePerFrameToFrameRate
@ stdcall MFBeginCreateFile(long long long wstr ptr ptr ptr)
@ stub MFBeginGetHostByName
@ stdcall MFBeginRegisterWorkQueueWithMMCSS(long wstr long ptr ptr)
@@ -71,7 +71,7 @@
@ stdcall MFCreateStreamDescriptor(long long ptr ptr)
@ stdcall MFCreateSystemTimeSource(ptr)
@ stub MFCreateSystemUnderlyingClock
-@ stdcall MFCreateTempFile(long long long ptr)
+@ stub MFCreateTempFile
@ stdcall MFCreateTrackedSample(ptr)
@ stdcall MFCreateTransformActivate(ptr)
@ stub MFCreateURLFromPath
@@ -162,7 +162,7 @@
@ stdcall MFTEnumEx(int128 long ptr ptr ptr ptr)
@ stdcall MFTGetInfo(int128 ptr ptr ptr ptr ptr ptr)
@ stdcall MFTRegister(int128 int128 wstr long long ptr long ptr ptr)
-@ stdcall MFTRegisterLocal(ptr ptr wstr long long ptr long ptr)
+@ stdcall MFTRegisterLocal(ptr ptr wstr long long ptr long ptr)
@ stdcall MFTRegisterLocalByCLSID(ptr ptr wstr long long ptr long ptr)
@ stdcall MFTUnregister(int128)
@ stdcall MFTUnregisterLocal(ptr)
diff --git a/dlls/mfplat/mfplat_private.h b/dlls/mfplat/mfplat_private.h
index 8418c8eb2ef..b646d9e7cbb 100644
--- wine/dlls/mfplat/mfplat_private.h
+++ wine/dlls/mfplat/mfplat_private.h
@@ -128,13 +128,11 @@ static inline const char *debugstr_propvar(const PROPVARIANT *v)
case VT_NULL:
return wine_dbg_sprintf("%p {VT_NULL}", v);
case VT_UI4:
- return wine_dbg_sprintf("%p {VT_UI4: %ld}", v, v->ulVal);
+ return wine_dbg_sprintf("%p {VT_UI4: %d}", v, v->ulVal);
case VT_UI8:
return wine_dbg_sprintf("%p {VT_UI8: %s}", v, wine_dbgstr_longlong(v->uhVal.QuadPart));
case VT_I8:
return wine_dbg_sprintf("%p {VT_I8: %s}", v, wine_dbgstr_longlong(v->hVal.QuadPart));
- case VT_R4:
- return wine_dbg_sprintf("%p {VT_R4: %.8e}", v, v->fltVal);
case VT_R8:
return wine_dbg_sprintf("%p {VT_R8: %lf}", v, v->dblVal);
case VT_CLSID:
@@ -180,7 +178,7 @@ static inline const char *debugstr_fourcc(DWORD format)
return wine_dbg_sprintf("%s", wine_dbgstr_an(formats[i].name, -1));
}
- return wine_dbg_sprintf("%#lx", format);
+ return wine_dbg_sprintf("%#x", format);
}
return wine_dbgstr_an((char *)&format, 4);
diff --git a/dlls/mfplat/quartz_parser.c b/dlls/mfplat/quartz_parser.c
new file mode 100644
index 00000000000..e9a3b00016d
--- /dev/null
+++ wine/dlls/mfplat/quartz_parser.c
@@ -0,0 +1,1945 @@
+/*
+ * DirectShow parser filters
+ *
+ * Copyright 2010 Maarten Lankhorst for CodeWeavers
+ * Copyright 2010 Aric Stewart for CodeWeavers
+ * Copyright 2019-2020 Zebediah Figura
+ *
+ * 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 "gst_guids.h"
+
+#include "amvideo.h"
+
+#include
+#include "dvdmedia.h"
+#include "mmreg.h"
+#include "ks.h"
+#include "initguid.h"
+#include "wmcodecdsp.h"
+#include "ksmedia.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(quartz);
+
+static const GUID MEDIASUBTYPE_CVID = {mmioFOURCC('c','v','i','d'), 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
+static const GUID MEDIASUBTYPE_MP3 = {WAVE_FORMAT_MPEGLAYER3, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
+
+struct parser
+{
+ struct strmbase_filter filter;
+ IAMStreamSelect IAMStreamSelect_iface;
+
+ struct strmbase_sink sink;
+ IAsyncReader *reader;
+
+ struct parser_source **sources;
+ unsigned int source_count;
+ BOOL enum_sink_first;
+
+ struct wg_parser *wg_parser;
+
+ /* FIXME: It would be nice to avoid duplicating these with strmbase.
+ * However, synchronization is tricky; we need access to be protected by a
+ * separate lock. */
+ bool streaming, sink_connected;
+
+ HANDLE read_thread;
+
+ BOOL (*init_gst)(struct parser *filter);
+ HRESULT (*source_query_accept)(struct parser_source *pin, const AM_MEDIA_TYPE *mt);
+ HRESULT (*source_get_media_type)(struct parser_source *pin, unsigned int index, AM_MEDIA_TYPE *mt);
+};
+
+struct parser_source
+{
+ struct strmbase_source pin;
+ IQualityControl IQualityControl_iface;
+
+ struct wg_parser_stream *wg_stream;
+
+ SourceSeeking seek;
+
+ CRITICAL_SECTION flushing_cs;
+ CONDITION_VARIABLE eos_cv;
+ HANDLE thread;
+
+ /* This variable is read and written by both the streaming thread and
+ * application threads. However, it is only written by the application
+ * thread when the streaming thread is not running, or when it is blocked
+ * by flushing_cs. */
+ bool need_segment;
+
+ bool eos;
+};
+
+static inline struct parser *impl_from_strmbase_filter(struct strmbase_filter *iface)
+{
+ return CONTAINING_RECORD(iface, struct parser, filter);
+}
+
+static const IMediaSeekingVtbl GST_Seeking_Vtbl;
+static const IQualityControlVtbl GSTOutPin_QualityControl_Vtbl;
+
+static struct parser_source *create_pin(struct parser *filter,
+ struct wg_parser_stream *stream, const WCHAR *name);
+static HRESULT GST_RemoveOutputPins(struct parser *This);
+static HRESULT WINAPI GST_ChangeCurrent(IMediaSeeking *iface);
+static HRESULT WINAPI GST_ChangeStop(IMediaSeeking *iface);
+static HRESULT WINAPI GST_ChangeRate(IMediaSeeking *iface);
+
+static bool amt_from_wg_format_audio(AM_MEDIA_TYPE *mt, const struct wg_format *format)
+{
+ mt->majortype = MEDIATYPE_Audio;
+ mt->formattype = FORMAT_WaveFormatEx;
+
+ switch (format->u.audio.format)
+ {
+ case WG_AUDIO_FORMAT_UNKNOWN:
+ return false;
+
+ case WG_AUDIO_FORMAT_MPEG1_LAYER1:
+ case WG_AUDIO_FORMAT_MPEG1_LAYER2:
+ {
+ MPEG1WAVEFORMAT *wave_format;
+
+ if (!(wave_format = CoTaskMemAlloc(sizeof(*wave_format))))
+ return false;
+ memset(wave_format, 0, sizeof(*wave_format));
+
+ mt->subtype = MEDIASUBTYPE_MPEG1AudioPayload;
+ mt->cbFormat = sizeof(*wave_format);
+ mt->pbFormat = (BYTE *)wave_format;
+ wave_format->wfx.wFormatTag = WAVE_FORMAT_MPEG;
+ wave_format->wfx.nChannels = format->u.audio.channels;
+ wave_format->wfx.nSamplesPerSec = format->u.audio.rate;
+ wave_format->wfx.cbSize = sizeof(*wave_format) - sizeof(WAVEFORMATEX);
+ wave_format->fwHeadLayer = (format->u.audio.format == WG_AUDIO_FORMAT_MPEG1_LAYER1 ? 1 : 2);
+ return true;
+ }
+
+ case WG_AUDIO_FORMAT_MPEG1_LAYER3:
+ {
+ MPEGLAYER3WAVEFORMAT *wave_format;
+
+ if (!(wave_format = CoTaskMemAlloc(sizeof(*wave_format))))
+ return false;
+ memset(wave_format, 0, sizeof(*wave_format));
+
+ mt->subtype = MEDIASUBTYPE_MP3;
+ mt->cbFormat = sizeof(*wave_format);
+ mt->pbFormat = (BYTE *)wave_format;
+ wave_format->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3;
+ wave_format->wfx.nChannels = format->u.audio.channels;
+ wave_format->wfx.nSamplesPerSec = format->u.audio.rate;
+ wave_format->wfx.cbSize = sizeof(*wave_format) - sizeof(WAVEFORMATEX);
+ /* FIXME: We can't get most of the MPEG data from the caps. We may have
+ * to manually parse the header. */
+ wave_format->wID = MPEGLAYER3_ID_MPEG;
+ wave_format->fdwFlags = MPEGLAYER3_FLAG_PADDING_ON;
+ wave_format->nFramesPerBlock = 1;
+ wave_format->nCodecDelay = 1393;
+ return true;
+ }
+
+ case WG_AUDIO_FORMAT_U8:
+ case WG_AUDIO_FORMAT_S16LE:
+ case WG_AUDIO_FORMAT_S24LE:
+ case WG_AUDIO_FORMAT_S32LE:
+ case WG_AUDIO_FORMAT_F32LE:
+ case WG_AUDIO_FORMAT_F64LE:
+ {
+ static const struct
+ {
+ bool is_float;
+ WORD depth;
+ }
+ format_table[] =
+ {
+ {0},
+ {false, 8},
+ {false, 16},
+ {false, 24},
+ {false, 32},
+ {true, 32},
+ {true, 64},
+ };
+
+ bool is_float;
+ WORD depth;
+
+ assert(format->u.audio.format < ARRAY_SIZE(format_table));
+ is_float = format_table[format->u.audio.format].is_float;
+ depth = format_table[format->u.audio.format].depth;
+
+ if (is_float || format->u.audio.channels > 2)
+ {
+ WAVEFORMATEXTENSIBLE *wave_format;
+
+ if (!(wave_format = CoTaskMemAlloc(sizeof(*wave_format))))
+ return false;
+ memset(wave_format, 0, sizeof(*wave_format));
+
+ mt->subtype = is_float ? MEDIASUBTYPE_IEEE_FLOAT : MEDIASUBTYPE_PCM;
+ mt->bFixedSizeSamples = TRUE;
+ mt->pbFormat = (BYTE *)wave_format;
+ mt->cbFormat = sizeof(*wave_format);
+ wave_format->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ wave_format->Format.nChannels = format->u.audio.channels;
+ wave_format->Format.nSamplesPerSec = format->u.audio.rate;
+ wave_format->Format.nAvgBytesPerSec = format->u.audio.rate * format->u.audio.channels * depth / 8;
+ wave_format->Format.nBlockAlign = format->u.audio.channels * depth / 8;
+ wave_format->Format.wBitsPerSample = depth;
+ wave_format->Format.cbSize = sizeof(*wave_format) - sizeof(WAVEFORMATEX);
+ wave_format->Samples.wValidBitsPerSample = depth;
+ wave_format->dwChannelMask = format->u.audio.channel_mask;
+ wave_format->SubFormat = is_float ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM;
+ mt->lSampleSize = wave_format->Format.nBlockAlign;
+ }
+ else
+ {
+ WAVEFORMATEX *wave_format;
+
+ if (!(wave_format = CoTaskMemAlloc(sizeof(*wave_format))))
+ return false;
+ memset(wave_format, 0, sizeof(*wave_format));
+
+ mt->subtype = MEDIASUBTYPE_PCM;
+ mt->bFixedSizeSamples = TRUE;
+ mt->pbFormat = (BYTE *)wave_format;
+ mt->cbFormat = sizeof(*wave_format);
+ wave_format->wFormatTag = WAVE_FORMAT_PCM;
+ wave_format->nChannels = format->u.audio.channels;
+ wave_format->nSamplesPerSec = format->u.audio.rate;
+ wave_format->nAvgBytesPerSec = format->u.audio.rate * format->u.audio.channels * depth / 8;
+ wave_format->nBlockAlign = format->u.audio.channels * depth / 8;
+ wave_format->wBitsPerSample = depth;
+ wave_format->cbSize = 0;
+ mt->lSampleSize = wave_format->nBlockAlign;
+ }
+ return true;
+ }
+ }
+
+ assert(0);
+ return false;
+}
+
+#define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1))
+
+unsigned int wg_format_get_max_size(const struct wg_format *format)
+{
+ switch (format->major_type)
+ {
+ case WG_MAJOR_TYPE_VIDEO:
+ {
+ unsigned int width = format->u.video.width, height = format->u.video.height;
+
+ switch (format->u.video.format)
+ {
+ case WG_VIDEO_FORMAT_BGRA:
+ case WG_VIDEO_FORMAT_BGRx:
+ case WG_VIDEO_FORMAT_AYUV:
+ return width * height * 4;
+
+ case WG_VIDEO_FORMAT_BGR:
+ return ALIGN(width * 3, 4) * height;
+
+ case WG_VIDEO_FORMAT_RGB15:
+ case WG_VIDEO_FORMAT_RGB16:
+ case WG_VIDEO_FORMAT_UYVY:
+ case WG_VIDEO_FORMAT_YUY2:
+ case WG_VIDEO_FORMAT_YVYU:
+ return ALIGN(width * 2, 4) * height;
+
+ case WG_VIDEO_FORMAT_I420:
+ case WG_VIDEO_FORMAT_YV12:
+ return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */
+ + 2 * ALIGN((width + 1) / 2, 4) * ((height + 1) / 2); /* U and V planes */
+
+ case WG_VIDEO_FORMAT_NV12:
+ return ALIGN(width, 4) * ALIGN(height, 2) /* Y plane */
+ + ALIGN(width, 4) * ((height + 1) / 2); /* U/V plane */
+
+ case WG_VIDEO_FORMAT_CINEPAK:
+ /* Both ffmpeg's encoder and a Cinepak file seen in the wild report
+ * 24 bpp. ffmpeg sets biSizeImage as below; others may be smaller,
+ * but as long as every sample fits into our allocator, we're fine. */
+ return width * height * 3;
+
+ case WG_VIDEO_FORMAT_UNKNOWN:
+ FIXME("Cannot guess maximum sample size for unknown video format.\n");
+ return 0;
+ }
+ break;
+ }
+
+ case WG_MAJOR_TYPE_AUDIO:
+ {
+ unsigned int rate = format->u.audio.rate, channels = format->u.audio.channels;
+
+ /* Actually we don't know how large of a sample GStreamer will give
+ * us. Hopefully 1 second is enough... */
+
+ switch (format->u.audio.format)
+ {
+ case WG_AUDIO_FORMAT_U8:
+ return rate * channels;
+
+ case WG_AUDIO_FORMAT_S16LE:
+ return rate * channels * 2;
+
+ case WG_AUDIO_FORMAT_S24LE:
+ return rate * channels * 3;
+
+ case WG_AUDIO_FORMAT_S32LE:
+ case WG_AUDIO_FORMAT_F32LE:
+ return rate * channels * 4;
+
+ case WG_AUDIO_FORMAT_F64LE:
+ return rate * channels * 8;
+
+ case WG_AUDIO_FORMAT_MPEG1_LAYER1:
+ return 56000;
+
+ case WG_AUDIO_FORMAT_MPEG1_LAYER2:
+ return 48000;
+
+ case WG_AUDIO_FORMAT_MPEG1_LAYER3:
+ return 40000;
+
+ case WG_AUDIO_FORMAT_UNKNOWN:
+ FIXME("Cannot guess maximum sample size for unknown audio format.\n");
+ return 0;
+ }
+ break;
+ }
+
+ case WG_MAJOR_TYPE_UNKNOWN:
+ FIXME("Cannot guess maximum sample size for unknown format.\n");
+ return 0;
+ }
+
+ assert(0);
+ return 0;
+}
+
+static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm)
+{
+ static const struct
+ {
+ const GUID *subtype;
+ DWORD compression;
+ WORD depth;
+ }
+ format_table[] =
+ {
+ {0},
+ {&MEDIASUBTYPE_ARGB32, BI_RGB, 32},
+ {&MEDIASUBTYPE_RGB32, BI_RGB, 32},
+ {&MEDIASUBTYPE_RGB24, BI_RGB, 24},
+ {&MEDIASUBTYPE_RGB555, BI_RGB, 16},
+ {&MEDIASUBTYPE_RGB565, BI_BITFIELDS, 16},
+ {&MEDIASUBTYPE_AYUV, mmioFOURCC('A','Y','U','V'), 32},
+ {&MEDIASUBTYPE_I420, mmioFOURCC('I','4','2','0'), 12},
+ {&MEDIASUBTYPE_NV12, mmioFOURCC('N','V','1','2'), 12},
+ {&MEDIASUBTYPE_UYVY, mmioFOURCC('U','Y','V','Y'), 16},
+ {&MEDIASUBTYPE_YUY2, mmioFOURCC('Y','U','Y','2'), 16},
+ {&MEDIASUBTYPE_YV12, mmioFOURCC('Y','V','1','2'), 12},
+ {&MEDIASUBTYPE_YVYU, mmioFOURCC('Y','V','Y','U'), 16},
+ {&MEDIASUBTYPE_CVID, mmioFOURCC('C','V','I','D'), 24},
+ };
+
+ VIDEOINFO *video_format;
+ uint32_t frame_time;
+
+ if (format->u.video.format == WG_VIDEO_FORMAT_UNKNOWN)
+ return false;
+
+ if (!(video_format = CoTaskMemAlloc(sizeof(*video_format))))
+ return false;
+
+ assert(format->u.video.format < ARRAY_SIZE(format_table));
+
+ mt->majortype = MEDIATYPE_Video;
+ mt->subtype = *format_table[format->u.video.format].subtype;
+ if (wm)
+ mt->bFixedSizeSamples = TRUE;
+ else
+ mt->bTemporalCompression = TRUE;
+ mt->lSampleSize = 1;
+ mt->formattype = FORMAT_VideoInfo;
+ mt->cbFormat = sizeof(VIDEOINFOHEADER);
+ mt->pbFormat = (BYTE *)video_format;
+
+ memset(video_format, 0, sizeof(*video_format));
+
+ if (wm)
+ {
+ SetRect(&video_format->rcSource, 0, 0, format->u.video.width, format->u.video.height);
+ video_format->rcTarget = video_format->rcSource;
+ }
+ if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1)
+ video_format->AvgTimePerFrame = frame_time;
+ video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ video_format->bmiHeader.biWidth = format->u.video.width;
+ video_format->bmiHeader.biHeight = format->u.video.height;
+ video_format->bmiHeader.biPlanes = 1;
+ video_format->bmiHeader.biBitCount = format_table[format->u.video.format].depth;
+ video_format->bmiHeader.biCompression = format_table[format->u.video.format].compression;
+ video_format->bmiHeader.biSizeImage = wg_format_get_max_size(format);
+
+ if (format->u.video.format == WG_VIDEO_FORMAT_RGB16)
+ {
+ mt->cbFormat = offsetof(VIDEOINFO, dwBitMasks[3]);
+ video_format->dwBitMasks[iRED] = 0xf800;
+ video_format->dwBitMasks[iGREEN] = 0x07e0;
+ video_format->dwBitMasks[iBLUE] = 0x001f;
+ }
+
+ return true;
+}
+
+bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm)
+{
+ memset(mt, 0, sizeof(*mt));
+
+ switch (format->major_type)
+ {
+ case WG_MAJOR_TYPE_UNKNOWN:
+ return false;
+
+ case WG_MAJOR_TYPE_AUDIO:
+ return amt_from_wg_format_audio(mt, format);
+
+ case WG_MAJOR_TYPE_VIDEO:
+ return amt_from_wg_format_video(mt, format, wm);
+ }
+
+ assert(0);
+ return false;
+}
+
+static bool amt_to_wg_format_audio(const AM_MEDIA_TYPE *mt, struct wg_format *format)
+{
+ static const struct
+ {
+ const GUID *subtype;
+ WORD depth;
+ enum wg_audio_format format;
+ }
+ format_map[] =
+ {
+ {&MEDIASUBTYPE_PCM, 8, WG_AUDIO_FORMAT_U8},
+ {&MEDIASUBTYPE_PCM, 16, WG_AUDIO_FORMAT_S16LE},
+ {&MEDIASUBTYPE_PCM, 24, WG_AUDIO_FORMAT_S24LE},
+ {&MEDIASUBTYPE_PCM, 32, WG_AUDIO_FORMAT_S32LE},
+ {&MEDIASUBTYPE_IEEE_FLOAT, 32, WG_AUDIO_FORMAT_F32LE},
+ {&MEDIASUBTYPE_IEEE_FLOAT, 64, WG_AUDIO_FORMAT_F64LE},
+ };
+
+ const WAVEFORMATEX *audio_format = (const WAVEFORMATEX *)mt->pbFormat;
+ unsigned int i;
+
+ if (!IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx))
+ {
+ FIXME("Unknown format type %s.\n", debugstr_guid(&mt->formattype));
+ return false;
+ }
+ if (mt->cbFormat < sizeof(WAVEFORMATEX) || !mt->pbFormat)
+ {
+ ERR("Unexpected format size %u.\n", mt->cbFormat);
+ return false;
+ }
+
+ format->major_type = WG_MAJOR_TYPE_AUDIO;
+ format->u.audio.channels = audio_format->nChannels;
+ format->u.audio.rate = audio_format->nSamplesPerSec;
+
+ if (audio_format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+ {
+ const WAVEFORMATEXTENSIBLE *ext_format = (const WAVEFORMATEXTENSIBLE *)mt->pbFormat;
+
+ format->u.audio.channel_mask = ext_format->dwChannelMask;
+ }
+ else
+ {
+ if (audio_format->nChannels == 1)
+ format->u.audio.channel_mask = KSAUDIO_SPEAKER_MONO;
+ else if (audio_format->nChannels == 2)
+ format->u.audio.channel_mask = KSAUDIO_SPEAKER_STEREO;
+ else
+ {
+ ERR("Unexpected channel count %u.\n", audio_format->nChannels);
+ return false;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(format_map); ++i)
+ {
+ if (IsEqualGUID(&mt->subtype, format_map[i].subtype)
+ && audio_format->wBitsPerSample == format_map[i].depth)
+ {
+ format->u.audio.format = format_map[i].format;
+ return true;
+ }
+ }
+
+ FIXME("Unknown subtype %s, depth %u.\n", debugstr_guid(&mt->subtype), audio_format->wBitsPerSample);
+ return false;
+}
+
+static bool amt_to_wg_format_audio_mpeg1(const AM_MEDIA_TYPE *mt, struct wg_format *format)
+{
+ const MPEG1WAVEFORMAT *audio_format = (const MPEG1WAVEFORMAT *)mt->pbFormat;
+
+ if (!IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx))
+ {
+ FIXME("Unknown format type %s.\n", debugstr_guid(&mt->formattype));
+ return false;
+ }
+ if (mt->cbFormat < sizeof(*audio_format) || !mt->pbFormat)
+ {
+ ERR("Unexpected format size %u.\n", mt->cbFormat);
+ return false;
+ }
+
+ format->major_type = WG_MAJOR_TYPE_AUDIO;
+ format->u.audio.channels = audio_format->wfx.nChannels;
+ format->u.audio.rate = audio_format->wfx.nSamplesPerSec;
+ if (audio_format->fwHeadLayer == 1)
+ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER1;
+ else if (audio_format->fwHeadLayer == 2)
+ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER2;
+ else if (audio_format->fwHeadLayer == 3)
+ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3;
+ else
+ return false;
+ return true;
+}
+
+static bool amt_to_wg_format_audio_mpeg1_layer3(const AM_MEDIA_TYPE *mt, struct wg_format *format)
+{
+ const MPEGLAYER3WAVEFORMAT *audio_format = (const MPEGLAYER3WAVEFORMAT *)mt->pbFormat;
+
+ if (!IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx))
+ {
+ FIXME("Unknown format type %s.\n", debugstr_guid(&mt->formattype));
+ return false;
+ }
+ if (mt->cbFormat < sizeof(*audio_format) || !mt->pbFormat)
+ {
+ ERR("Unexpected format size %u.\n", mt->cbFormat);
+ return false;
+ }
+
+ format->major_type = WG_MAJOR_TYPE_AUDIO;
+ format->u.audio.channels = audio_format->wfx.nChannels;
+ format->u.audio.rate = audio_format->wfx.nSamplesPerSec;
+ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3;
+ return true;
+}
+
+static bool amt_to_wg_format_video(const AM_MEDIA_TYPE *mt, struct wg_format *format)
+{
+ static const struct
+ {
+ const GUID *subtype;
+ enum wg_video_format format;
+ }
+ format_map[] =
+ {
+ {&MEDIASUBTYPE_ARGB32, WG_VIDEO_FORMAT_BGRA},
+ {&MEDIASUBTYPE_RGB32, WG_VIDEO_FORMAT_BGRx},
+ {&MEDIASUBTYPE_RGB24, WG_VIDEO_FORMAT_BGR},
+ {&MEDIASUBTYPE_RGB555, WG_VIDEO_FORMAT_RGB15},
+ {&MEDIASUBTYPE_RGB565, WG_VIDEO_FORMAT_RGB16},
+ {&MEDIASUBTYPE_AYUV, WG_VIDEO_FORMAT_AYUV},
+ {&MEDIASUBTYPE_I420, WG_VIDEO_FORMAT_I420},
+ {&MEDIASUBTYPE_NV12, WG_VIDEO_FORMAT_NV12},
+ {&MEDIASUBTYPE_UYVY, WG_VIDEO_FORMAT_UYVY},
+ {&MEDIASUBTYPE_YUY2, WG_VIDEO_FORMAT_YUY2},
+ {&MEDIASUBTYPE_YV12, WG_VIDEO_FORMAT_YV12},
+ {&MEDIASUBTYPE_YVYU, WG_VIDEO_FORMAT_YVYU},
+ {&MEDIASUBTYPE_CVID, WG_VIDEO_FORMAT_CINEPAK},
+ };
+
+ const VIDEOINFOHEADER *video_format = (const VIDEOINFOHEADER *)mt->pbFormat;
+ unsigned int i;
+
+ if (!IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo))
+ {
+ FIXME("Unknown format type %s.\n", debugstr_guid(&mt->formattype));
+ return false;
+ }
+ if (mt->cbFormat < sizeof(VIDEOINFOHEADER) || !mt->pbFormat)
+ {
+ ERR("Unexpected format size %u.\n", mt->cbFormat);
+ return false;
+ }
+
+ format->major_type = WG_MAJOR_TYPE_VIDEO;
+ format->u.video.width = video_format->bmiHeader.biWidth;
+ format->u.video.height = video_format->bmiHeader.biHeight;
+ format->u.video.fps_n = 10000000;
+ format->u.video.fps_d = video_format->AvgTimePerFrame;
+
+ for (i = 0; i < ARRAY_SIZE(format_map); ++i)
+ {
+ if (IsEqualGUID(&mt->subtype, format_map[i].subtype))
+ {
+ format->u.video.format = format_map[i].format;
+ return true;
+ }
+ }
+
+ FIXME("Unknown subtype %s.\n", debugstr_guid(&mt->subtype));
+ return false;
+}
+
+bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format)
+{
+ memset(format, 0, sizeof(*format));
+
+ if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Video))
+ return amt_to_wg_format_video(mt, format);
+ if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio))
+ {
+ if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1AudioPayload))
+ return amt_to_wg_format_audio_mpeg1(mt, format);
+ if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MP3))
+ return amt_to_wg_format_audio_mpeg1_layer3(mt, format);
+ return amt_to_wg_format_audio(mt, format);
+ }
+
+ FIXME("Unknown major type %s.\n", debugstr_guid(&mt->majortype));
+ return false;
+}
+
+/*
+ * scale_uint64() is based on gst_util_scale_int() from GStreamer, which is
+ * covered by the following license:
+ *
+ * GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen
+ * 2000 Wim Taymans
+ * 2002 Thomas Vander Stichele
+ * 2004 Wim Taymans
+ * 2015 Jan Schmidt
+ *
+ * gstutils.c: Utility functions
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ */
+static uint64_t scale_uint64(uint64_t value, uint32_t numerator, uint32_t denominator)
+{
+ ULARGE_INTEGER i, high, low;
+
+ if (!value)
+ return 0;
+
+ i.QuadPart = value;
+ low.QuadPart = (ULONGLONG)i.u.LowPart * numerator;
+ high.QuadPart = (ULONGLONG)i.u.HighPart * numerator + low.u.HighPart;
+ low.u.HighPart = 0;
+
+ if (high.u.HighPart >= denominator)
+ return ULLONG_MAX;
+
+ low.QuadPart += (high.QuadPart % denominator) << 32;
+ return ((high.QuadPart / denominator) << 32) + (low.QuadPart / denominator);
+}
+
+/* Fill and send a single IMediaSample. */
+static HRESULT send_sample(struct parser_source *pin, IMediaSample *sample,
+ const struct wg_parser_buffer *buffer, uint32_t offset, uint32_t size, DWORD bytes_per_second)
+{
+ HRESULT hr;
+ BYTE *ptr = NULL;
+
+ TRACE("offset %u, size %u, sample size %u\n", offset, size, IMediaSample_GetSize(sample));
+
+ hr = IMediaSample_SetActualDataLength(sample, size);
+ if(FAILED(hr)){
+ WARN("SetActualDataLength failed: %08x\n", hr);
+ return hr;
+ }
+
+ IMediaSample_GetPointer(sample, &ptr);
+
+ if (!wg_parser_stream_copy_buffer(pin->wg_stream, ptr, offset, size))
+ {
+ /* The GStreamer pin has been flushed. */
+ return S_OK;
+ }
+
+ if (buffer->has_pts)
+ {
+ REFERENCE_TIME start_pts = buffer->pts;
+
+ if (offset)
+ start_pts += scale_uint64(offset, 10000000, bytes_per_second);
+ start_pts -= pin->seek.llCurrent;
+ start_pts *= pin->seek.dRate;
+
+ if (buffer->has_duration)
+ {
+ REFERENCE_TIME end_pts = buffer->pts + buffer->duration;
+
+ if (offset + size < buffer->size)
+ end_pts = buffer->pts + scale_uint64(offset + size, 10000000, bytes_per_second);
+ end_pts -= pin->seek.llCurrent;
+ end_pts *= pin->seek.dRate;
+
+ IMediaSample_SetTime(sample, &start_pts, &end_pts);
+ IMediaSample_SetMediaTime(sample, &start_pts, &end_pts);
+ }
+ else
+ {
+ IMediaSample_SetTime(sample, &start_pts, NULL);
+ IMediaSample_SetMediaTime(sample, NULL, NULL);
+ }
+ }
+ else
+ {
+ IMediaSample_SetTime(sample, NULL, NULL);
+ IMediaSample_SetMediaTime(sample, NULL, NULL);
+ }
+
+ IMediaSample_SetDiscontinuity(sample, !offset && buffer->discontinuity);
+ IMediaSample_SetPreroll(sample, buffer->preroll);
+ IMediaSample_SetSyncPoint(sample, !buffer->delta);
+
+ if (!pin->pin.pin.peer)
+ hr = VFW_E_NOT_CONNECTED;
+ else
+ hr = IMemInputPin_Receive(pin->pin.pMemInputPin, sample);
+
+ TRACE("sending sample returned: %08x\n", hr);
+
+ return hr;
+}
+
+/* Send a single GStreamer buffer (splitting it into multiple IMediaSamples if
+ * necessary). */
+static void send_buffer(struct parser_source *pin, const struct wg_parser_buffer *buffer)
+{
+ HRESULT hr;
+ IMediaSample *sample;
+
+ if (pin->need_segment)
+ {
+ if (FAILED(hr = IPin_NewSegment(pin->pin.pin.peer,
+ pin->seek.llCurrent, pin->seek.llStop, pin->seek.dRate)))
+ WARN("Failed to deliver new segment, hr %#x.\n", hr);
+ pin->need_segment = false;
+ }
+
+ if (IsEqualGUID(&pin->pin.pin.mt.formattype, &FORMAT_WaveFormatEx)
+ && (IsEqualGUID(&pin->pin.pin.mt.subtype, &MEDIASUBTYPE_PCM)
+ || IsEqualGUID(&pin->pin.pin.mt.subtype, &MEDIASUBTYPE_IEEE_FLOAT)))
+ {
+ WAVEFORMATEX *format = (WAVEFORMATEX *)pin->pin.pin.mt.pbFormat;
+ uint32_t offset = 0;
+
+ while (offset < buffer->size)
+ {
+ uint32_t advance;
+
+ hr = BaseOutputPinImpl_GetDeliveryBuffer(&pin->pin, &sample, NULL, NULL, 0);
+
+ if (FAILED(hr))
+ {
+ if (hr != VFW_E_NOT_CONNECTED)
+ ERR("Could not get a delivery buffer (%x), returning GST_FLOW_FLUSHING\n", hr);
+ break;
+ }
+
+ advance = min(IMediaSample_GetSize(sample), buffer->size - offset);
+
+ hr = send_sample(pin, sample, buffer, offset, advance, format->nAvgBytesPerSec);
+
+ IMediaSample_Release(sample);
+
+ if (FAILED(hr))
+ break;
+
+ offset += advance;
+ }
+ }
+ else
+ {
+ hr = BaseOutputPinImpl_GetDeliveryBuffer(&pin->pin, &sample, NULL, NULL, 0);
+
+ if (FAILED(hr))
+ {
+ if (hr != VFW_E_NOT_CONNECTED)
+ ERR("Could not get a delivery buffer (%x), returning GST_FLOW_FLUSHING\n", hr);
+ }
+ else
+ {
+ hr = send_sample(pin, sample, buffer, 0, buffer->size, 0);
+
+ IMediaSample_Release(sample);
+ }
+ }
+
+ wg_parser_stream_release_buffer(pin->wg_stream);
+}
+
+static DWORD CALLBACK stream_thread(void *arg)
+{
+ struct parser_source *pin = arg;
+ struct parser *filter = impl_from_strmbase_filter(pin->pin.pin.filter);
+
+ TRACE("Starting streaming thread for pin %p.\n", pin);
+
+ while (filter->streaming)
+ {
+ struct wg_parser_buffer buffer;
+
+ EnterCriticalSection(&pin->flushing_cs);
+
+ if (pin->eos)
+ {
+ SleepConditionVariableCS(&pin->eos_cv, &pin->flushing_cs, INFINITE);
+ LeaveCriticalSection(&pin->flushing_cs);
+ continue;
+ }
+
+ if (wg_parser_stream_get_buffer(pin->wg_stream, &buffer))
+ {
+ send_buffer(pin, &buffer);
+ }
+ else
+ {
+ TRACE("Got EOS.\n");
+ IPin_EndOfStream(pin->pin.pin.peer);
+ pin->eos = true;
+ }
+
+ LeaveCriticalSection(&pin->flushing_cs);
+ }
+
+ TRACE("Streaming stopped; exiting.\n");
+ return 0;
+}
+
+static DWORD CALLBACK read_thread(void *arg)
+{
+ struct parser *filter = arg;
+ LONGLONG file_size, unused;
+ size_t buffer_size = 4096;
+ void *data = NULL;
+
+ if (!(data = malloc(buffer_size)))
+ return 0;
+
+ IAsyncReader_Length(filter->reader, &file_size, &unused);
+
+ TRACE("Starting read thread for filter %p.\n", filter);
+
+ while (filter->sink_connected)
+ {
+ uint64_t offset;
+ uint32_t size;
+ HRESULT hr;
+
+ if (!wg_parser_get_next_read_offset(filter->wg_parser, &offset, &size))
+ continue;
+
+ if (offset >= file_size)
+ size = 0;
+ else if (offset + size >= file_size)
+ size = file_size - offset;
+
+ if (!array_reserve(&data, &buffer_size, size, 1))
+ {
+ free(data);
+ return 0;
+ }
+
+ hr = IAsyncReader_SyncRead(filter->reader, offset, size, data);
+ if (FAILED(hr))
+ ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr);
+
+ wg_parser_push_data(filter->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, size);
+ }
+
+ free(data);
+ TRACE("Streaming stopped; exiting.\n");
+ return 0;
+}
+
+static inline struct parser_source *impl_from_IMediaSeeking(IMediaSeeking *iface)
+{
+ return CONTAINING_RECORD(iface, struct parser_source, seek.IMediaSeeking_iface);
+}
+
+static struct strmbase_pin *parser_get_pin(struct strmbase_filter *base, unsigned int index)
+{
+ struct parser *filter = impl_from_strmbase_filter(base);
+
+ if (filter->enum_sink_first)
+ {
+ if (!index)
+ return &filter->sink.pin;
+ else if (index <= filter->source_count)
+ return &filter->sources[index - 1]->pin.pin;
+ }
+ else
+ {
+ if (index < filter->source_count)
+ return &filter->sources[index]->pin.pin;
+ else if (index == filter->source_count)
+ return &filter->sink.pin;
+ }
+ return NULL;
+}
+
+static void parser_destroy(struct strmbase_filter *iface)
+{
+ struct parser *filter = impl_from_strmbase_filter(iface);
+ HRESULT hr;
+
+ /* Don't need to clean up output pins, disconnecting input pin will do that */
+ if (filter->sink.pin.peer)
+ {
+ hr = IPin_Disconnect(filter->sink.pin.peer);
+ assert(hr == S_OK);
+ hr = IPin_Disconnect(&filter->sink.pin.IPin_iface);
+ assert(hr == S_OK);
+ }
+
+ if (filter->reader)
+ IAsyncReader_Release(filter->reader);
+ filter->reader = NULL;
+
+ wg_parser_destroy(filter->wg_parser);
+
+ strmbase_sink_cleanup(&filter->sink);
+ strmbase_filter_cleanup(&filter->filter);
+ free(filter);
+}
+
+static HRESULT parser_init_stream(struct strmbase_filter *iface)
+{
+ struct parser *filter = impl_from_strmbase_filter(iface);
+ DWORD stop_flags = AM_SEEKING_NoPositioning;
+ const SourceSeeking *seeking;
+ unsigned int i;
+
+ if (!filter->sink_connected)
+ return S_OK;
+
+ filter->streaming = true;
+
+ /* DirectShow retains the old seek positions, but resets to them every time
+ * it transitions from stopped -> paused. */
+
+ seeking = &filter->sources[0]->seek;
+ if (seeking->llStop)
+ stop_flags = AM_SEEKING_AbsolutePositioning;
+ wg_parser_stream_seek(filter->sources[0]->wg_stream, seeking->dRate,
+ seeking->llCurrent, seeking->llStop, AM_SEEKING_AbsolutePositioning, stop_flags);
+
+ for (i = 0; i < filter->source_count; ++i)
+ {
+ struct parser_source *pin = filter->sources[i];
+ HRESULT hr;
+
+ if (!pin->pin.pin.peer)
+ continue;
+
+ if (FAILED(hr = IMemAllocator_Commit(pin->pin.pAllocator)))
+ ERR("Failed to commit allocator, hr %#x.\n", hr);
+
+ pin->need_segment = true;
+ pin->eos = false;
+
+ pin->thread = CreateThread(NULL, 0, stream_thread, pin, 0, NULL);
+ }
+
+ return S_OK;
+}
+
+static HRESULT parser_cleanup_stream(struct strmbase_filter *iface)
+{
+ struct parser *filter = impl_from_strmbase_filter(iface);
+ unsigned int i;
+
+ if (!filter->sink_connected)
+ return S_OK;
+
+ filter->streaming = false;
+
+ for (i = 0; i < filter->source_count; ++i)
+ {
+ struct parser_source *pin = filter->sources[i];
+
+ if (!pin->pin.pin.peer)
+ continue;
+
+ IMemAllocator_Decommit(pin->pin.pAllocator);
+
+ WakeConditionVariable(&pin->eos_cv);
+ WaitForSingleObject(pin->thread, INFINITE);
+ CloseHandle(pin->thread);
+ pin->thread = NULL;
+ }
+
+ return S_OK;
+}
+
+static const struct strmbase_filter_ops filter_ops =
+{
+ .filter_get_pin = parser_get_pin,
+ .filter_destroy = parser_destroy,
+ .filter_init_stream = parser_init_stream,
+ .filter_cleanup_stream = parser_cleanup_stream,
+};
+
+static inline struct parser *impl_from_strmbase_sink(struct strmbase_sink *iface)
+{
+ return CONTAINING_RECORD(iface, struct parser, sink);
+}
+
+static HRESULT sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
+{
+ if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Stream))
+ return S_OK;
+ return S_FALSE;
+}
+
+static HRESULT parser_sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *pmt)
+{
+ struct parser *filter = impl_from_strmbase_sink(iface);
+ LONGLONG file_size, unused;
+ HRESULT hr = S_OK;
+ unsigned int i;
+
+ filter->reader = NULL;
+ if (FAILED(hr = IPin_QueryInterface(peer, &IID_IAsyncReader, (void **)&filter->reader)))
+ return hr;
+
+ IAsyncReader_Length(filter->reader, &file_size, &unused);
+
+ filter->sink_connected = true;
+ filter->read_thread = CreateThread(NULL, 0, read_thread, filter, 0, NULL);
+
+ if (FAILED(hr = wg_parser_connect(filter->wg_parser, file_size)))
+ goto err;
+
+ if (!filter->init_gst(filter))
+ {
+ hr = E_FAIL;
+ goto err;
+ }
+
+ for (i = 0; i < filter->source_count; ++i)
+ {
+ struct parser_source *pin = filter->sources[i];
+
+ pin->seek.llDuration = pin->seek.llStop = wg_parser_stream_get_duration(pin->wg_stream);
+ pin->seek.llCurrent = 0;
+ }
+
+ return S_OK;
+err:
+ GST_RemoveOutputPins(filter);
+ IAsyncReader_Release(filter->reader);
+ filter->reader = NULL;
+ return hr;
+}
+
+static void parser_sink_disconnect(struct strmbase_sink *iface)
+{
+ struct parser *filter = impl_from_strmbase_sink(iface);
+
+ GST_RemoveOutputPins(filter);
+
+ IAsyncReader_Release(filter->reader);
+ filter->reader = NULL;
+}
+
+static const struct strmbase_sink_ops sink_ops =
+{
+ .base.pin_query_accept = sink_query_accept,
+ .sink_connect = parser_sink_connect,
+ .sink_disconnect = parser_sink_disconnect,
+};
+
+static BOOL decodebin_parser_filter_init_gst(struct parser *filter)
+{
+ struct wg_parser *parser = filter->wg_parser;
+ const char *sgi = getenv("SteamGameId");
+ const WCHAR *format;
+ unsigned int i, stream_count;
+ WCHAR source_name[20];
+
+ /* King of Fighters XIII requests the WMV decoder filter pins by name
+ * to connect them to a Sample Grabber filter.
+ */
+ format = (sgi && !strcmp(sgi, "222940")) ? L"out%u" : L"Stream %02u";
+
+ stream_count = wg_parser_get_stream_count(parser);
+ for (i = 0; i < stream_count; ++i)
+ {
+ swprintf(source_name, ARRAY_SIZE(source_name), format, i);
+ if (!create_pin(filter, wg_parser_get_stream(parser, i), source_name))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static HRESULT decodebin_parser_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE *mt)
+{
+ struct wg_format format;
+
+ /* At least make sure we can convert it to wg_format. */
+ return amt_to_wg_format(mt, &format) ? S_OK : S_FALSE;
+}
+
+static HRESULT decodebin_parser_source_get_media_type(struct parser_source *pin,
+ unsigned int index, AM_MEDIA_TYPE *mt)
+{
+ struct wg_format format;
+
+ static const enum wg_video_format video_formats[] =
+ {
+ /* Try to prefer YUV formats over RGB ones. Most decoders output