Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
December 2019
- 73 participants
- 1394 messages
[PATCH 5/5] qedit/samplegrabber: Use BaseFilterImpl_JoinFilterGraph().
by Zebediah Figura
Manual testing shows that adding or removing the filter does not affect whether
it is in one-shot mode.
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/qedit/samplegrabber.c | 23 +----------------------
1 file changed, 1 insertion(+), 22 deletions(-)
diff --git a/dlls/qedit/samplegrabber.c b/dlls/qedit/samplegrabber.c
index 9dd8c02b23d..af05966c140 100644
--- a/dlls/qedit/samplegrabber.c
+++ b/dlls/qedit/samplegrabber.c
@@ -66,11 +66,6 @@ static inline SG_Impl *impl_from_strmbase_filter(struct strmbase_filter *iface)
return CONTAINING_RECORD(iface, SG_Impl, filter);
}
-static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface)
-{
- return CONTAINING_RECORD(iface, SG_Impl, filter.IBaseFilter_iface);
-}
-
static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface)
{
return CONTAINING_RECORD(iface, SG_Impl, ISampleGrabber_iface);
@@ -198,22 +193,6 @@ static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample)
}
}
-/* IBaseFilter */
-static HRESULT WINAPI
-SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name)
-{
- SG_Impl *This = impl_from_IBaseFilter(iface);
-
- TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name));
-
- BaseFilterImpl_JoinFilterGraph(iface, graph, name);
- This->oneShot = OneShot_None;
-
- return S_OK;
-}
-
-/* SampleGrabber implementation of ISampleGrabber interface */
-
/* IUnknown */
static HRESULT WINAPI
SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppv)
@@ -525,7 +504,7 @@ static const IBaseFilterVtbl IBaseFilter_VTable =
BaseFilterImpl_EnumPins,
BaseFilterImpl_FindPin,
BaseFilterImpl_QueryFilterInfo,
- SampleGrabber_IBaseFilter_JoinFilterGraph,
+ BaseFilterImpl_JoinFilterGraph,
BaseFilterImpl_QueryVendorInfo,
};
--
2.23.0
Dec. 4, 2019
[PATCH 4/5] wineqtdecoder: Don't expose IMediaSeeking from the filter.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/wineqtdecoder/qtsplitter.c | 35 ++-------------------------------
1 file changed, 2 insertions(+), 33 deletions(-)
diff --git a/dlls/wineqtdecoder/qtsplitter.c b/dlls/wineqtdecoder/qtsplitter.c
index c021fec8af3..28ea36785a8 100644
--- a/dlls/wineqtdecoder/qtsplitter.c
+++ b/dlls/wineqtdecoder/qtsplitter.c
@@ -381,37 +381,6 @@ IUnknown * CALLBACK QTSplitter_create(IUnknown *outer, HRESULT *phr)
return &This->filter.IUnknown_inner;
}
-static HRESULT WINAPI QT_QueryInterface(IBaseFilter *iface, REFIID riid, LPVOID *ppv)
-{
- QTSplitter *This = impl_from_IBaseFilter(iface);
- TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
-
- *ppv = NULL;
-
- if (IsEqualIID(riid, &IID_IUnknown))
- *ppv = This;
- else if (IsEqualIID(riid, &IID_IPersist))
- *ppv = This;
- else if (IsEqualIID(riid, &IID_IMediaFilter))
- *ppv = This;
- else if (IsEqualIID(riid, &IID_IBaseFilter))
- *ppv = This;
- else if (IsEqualIID(riid, &IID_IMediaSeeking))
- *ppv = &This->sourceSeeking;
-
- if (*ppv)
- {
- IUnknown_AddRef((IUnknown *)(*ppv));
- return S_OK;
- }
-
- if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow) &&
- !IsEqualIID(riid, &IID_IAMFilterMiscFlags))
- FIXME("No interface for %s!\n", debugstr_guid(riid));
-
- return E_NOINTERFACE;
-}
-
static OSErr QT_Create_Extract_Session(QTSplitter *filter)
{
AudioStreamBasicDescription aDesc;
@@ -753,7 +722,7 @@ audio_error:
}
static const IBaseFilterVtbl QT_Vtbl = {
- QT_QueryInterface,
+ BaseFilterImpl_QueryInterface,
BaseFilterImpl_AddRef,
BaseFilterImpl_Release,
BaseFilterImpl_GetClassID,
@@ -1220,7 +1189,7 @@ static HRESULT WINAPI QTOutPin_QueryInterface(IPin *iface, REFIID riid, void **p
else if (IsEqualIID(riid, &IID_IPin))
*ppv = iface;
else if (IsEqualIID(riid, &IID_IMediaSeeking))
- return IBaseFilter_QueryInterface(&This->pin.pin.filter->IBaseFilter_iface, &IID_IMediaSeeking, ppv);
+ *ppv = &This->sourceSeeking.IMediaSeeking_iface;
else if (IsEqualIID(riid, &IID_IQualityControl))
*ppv = &This->IQualityControl_iface;
--
2.23.0
Dec. 4, 2019
[PATCH 3/5] wineqtdecoder: Don't expose IMediaSeeking from the sink pin.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/wineqtdecoder/qtsplitter.c | 28 +---------------------------
1 file changed, 1 insertion(+), 27 deletions(-)
diff --git a/dlls/wineqtdecoder/qtsplitter.c b/dlls/wineqtdecoder/qtsplitter.c
index f22e014e1b9..c021fec8af3 100644
--- a/dlls/wineqtdecoder/qtsplitter.c
+++ b/dlls/wineqtdecoder/qtsplitter.c
@@ -1168,34 +1168,8 @@ static HRESULT WINAPI QTInPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REF
return S_OK;
}
-static HRESULT WINAPI QTInPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
-{
- QTInPin *This = impl_from_IPin(iface);
-
- TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
-
- *ppv = NULL;
-
- if (IsEqualIID(riid, &IID_IUnknown))
- *ppv = iface;
- else if (IsEqualIID(riid, &IID_IPin))
- *ppv = iface;
- else if (IsEqualIID(riid, &IID_IMediaSeeking))
- return IBaseFilter_QueryInterface(&This->pin.filter->IBaseFilter_iface, &IID_IMediaSeeking, ppv);
-
- if (*ppv)
- {
- IUnknown_AddRef((IUnknown *)(*ppv));
- return S_OK;
- }
-
- FIXME("No interface for %s!\n", debugstr_guid(riid));
-
- return E_NOINTERFACE;
-}
-
static const IPinVtbl QT_InputPin_Vtbl = {
- QTInPin_QueryInterface,
+ BasePinImpl_QueryInterface,
BasePinImpl_AddRef,
BasePinImpl_Release,
BaseInputPinImpl_Connect,
--
2.23.0
Dec. 4, 2019
[PATCH 2/5] wineqtdecoder: Use strmbase filter state change methods.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
Not compile-tested.
dlls/wineqtdecoder/qtsplitter.c | 107 ++++++++++++--------------------
1 file changed, 40 insertions(+), 67 deletions(-)
diff --git a/dlls/wineqtdecoder/qtsplitter.c b/dlls/wineqtdecoder/qtsplitter.c
index 81e18d34205..f22e014e1b9 100644
--- a/dlls/wineqtdecoder/qtsplitter.c
+++ b/dlls/wineqtdecoder/qtsplitter.c
@@ -160,7 +160,6 @@ typedef struct QTSplitter {
HANDLE runEvent;
DWORD outputSize;
- FILTER_STATE state;
CRITICAL_SECTION csReceive;
SourceSeeking sourceSeeking;
@@ -281,10 +280,46 @@ static void qt_splitter_destroy(struct strmbase_filter *iface)
CoTaskMemFree(filter);
}
+static HRESULT qt_splitter_start_stream(struct strmbase_filter *iface, REFERENCE_TIME time)
+{
+ QTSplitter *filter = impl_from_strmbase_filter(iface);
+ HRESULT hr = VFW_E_NOT_CONNECTED, pin_hr;
+
+ EnterCriticalSection(&This->csReceive);
+
+ if (filter->pVideo_Pin)
+ pin_hr = BaseOutputPinImpl_Active(&filter->pVideo_Pin->pin);
+ if (SUCCEEDED(pin_hr))
+ hr = pin_hr;
+ if (filter->pAudio_Pin)
+ pin_hr = BaseOutputPinImpl_Active(&filter->pAudio_Pin->pin);
+ if (SUCCEEDED(pin_hr))
+ hr = pin_hr;
+ SetEvent(filter->runEvent);
+
+ LeaveCriticalSection(&This->csReceive);
+
+ return hr;
+}
+
+static HRESULT qt_splitter_cleanup_stream(struct strmbase_filter *iface)
+{
+ QTSplitter *filter = impl_from_strmbase_filter(iface);
+
+ EnterCriticalSection(&This->csReceive);
+ IAsyncReader_BeginFlush(filter->pInputPin.pReader);
+ IAsyncReader_EndFlush(filter->pInputPin.pReader);
+ LeaveCriticalSection(&This->csReceive);
+
+ return S_OK;
+}
+
static const struct strmbase_filter_ops filter_ops =
{
.filter_get_pin = qt_splitter_get_pin,
.filter_destroy = qt_splitter_destroy,
+ .filter_start_stream = qt_splitter_start_stream,
+ .filter_cleanup_stream = qt_splitter_cleanup_stream,
};
static HRESULT sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
@@ -329,7 +364,6 @@ IUnknown * CALLBACK QTSplitter_create(IUnknown *outer, HRESULT *phr)
This->pVideo_Pin = NULL;
This->pAudio_Pin = NULL;
- This->state = State_Stopped;
This->aSession = NULL;
This->runEvent = CreateEventW(NULL, 0, 0, NULL);
@@ -378,28 +412,6 @@ static HRESULT WINAPI QT_QueryInterface(IBaseFilter *iface, REFIID riid, LPVOID
return E_NOINTERFACE;
}
-static HRESULT WINAPI QT_Stop(IBaseFilter *iface)
-{
- QTSplitter *This = impl_from_IBaseFilter(iface);
-
- TRACE("()\n");
-
- EnterCriticalSection(&This->csReceive);
- IAsyncReader_BeginFlush(This->pInputPin.pReader);
- IAsyncReader_EndFlush(This->pInputPin.pReader);
- LeaveCriticalSection(&This->csReceive);
-
- return S_OK;
-}
-
-static HRESULT WINAPI QT_Pause(IBaseFilter *iface)
-{
- HRESULT hr = S_OK;
- TRACE("()\n");
-
- return hr;
-}
-
static OSErr QT_Create_Extract_Session(QTSplitter *filter)
{
AudioStreamBasicDescription aDesc;
@@ -534,7 +546,6 @@ static DWORD WINAPI QTSplitter_thread(LPVOID data)
return 0;
}
- This->state = State_Running;
/* Prime the pump: Needed for MPEG streams */
GetMovieNextInterestingTime(This->pQTMovie, nextTimeEdgeOK | nextTimeStep, 0, NULL, This->movie_time, 1, &next_time, NULL);
@@ -733,7 +744,6 @@ audio_error:
LeaveCriticalSection(&This->csReceive);
} while (hr == S_OK);
- This->state = State_Stopped;
if (This->pAudio_Pin)
OutputQueue_EOS(This->pAudio_Pin->queue);
if (This->pVideo_Pin)
@@ -742,52 +752,15 @@ audio_error:
return hr;
}
-static HRESULT WINAPI QT_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
-{
- HRESULT hr = S_OK;
- QTSplitter *This = impl_from_IBaseFilter(iface);
- HRESULT hr_any = VFW_E_NOT_CONNECTED;
-
- TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
-
- EnterCriticalSection(&This->csReceive);
-
- if (This->pVideo_Pin)
- hr = BaseOutputPinImpl_Active(&This->pVideo_Pin->pin);
- if (SUCCEEDED(hr))
- hr_any = hr;
- if (This->pAudio_Pin)
- hr = BaseOutputPinImpl_Active(&This->pAudio_Pin->pin);
- if (SUCCEEDED(hr))
- hr_any = hr;
-
- hr = hr_any;
-
- SetEvent(This->runEvent);
- LeaveCriticalSection(&This->csReceive);
-
- return hr;
-}
-
-static HRESULT WINAPI QT_GetState(IBaseFilter *iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
-{
- QTSplitter *This = impl_from_IBaseFilter(iface);
- TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState);
-
- *pState = This->state;
-
- return S_OK;
-}
-
static const IBaseFilterVtbl QT_Vtbl = {
QT_QueryInterface,
BaseFilterImpl_AddRef,
BaseFilterImpl_Release,
BaseFilterImpl_GetClassID,
- QT_Stop,
- QT_Pause,
- QT_Run,
- QT_GetState,
+ BaseFilterImpl_Stop,
+ BaseFilterImpl_Pause,
+ BaseFilterImpl_Run,
+ BaseFilterImpl_GetState,
BaseFilterImpl_SetSyncSource,
BaseFilterImpl_GetSyncSource,
BaseFilterImpl_EnumPins,
--
2.23.0
Dec. 4, 2019
[PATCH 1/5] winegstreamer: Fix the timeout passed to gst_element_get_state().
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/winegstreamer/gstdemux.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/gstdemux.c b/dlls/winegstreamer/gstdemux.c
index 753286a7189..e024d271974 100644
--- a/dlls/winegstreamer/gstdemux.c
+++ b/dlls/winegstreamer/gstdemux.c
@@ -1324,7 +1324,7 @@ static HRESULT gstdemux_wait_state(struct strmbase_filter *iface, DWORD timeout)
return S_OK;
ret = gst_element_get_state(filter->container, NULL, NULL,
- timeout == INFINITE ? GST_CLOCK_TIME_NONE : timeout * 1000);
+ timeout == INFINITE ? GST_CLOCK_TIME_NONE : timeout * 1000000);
if (ret == GST_STATE_CHANGE_FAILURE)
{
ERR("Failed to get state.\n");
--
2.23.0
Dec. 4, 2019
[PATCH v4 2/2] ntdll/tests: Add tests for UMIP instructions.
by Brendan Shanks
Signed-off-by: Brendan Shanks <bshanks(a)codeweavers.com>
---
dlls/ntdll/tests/exception.c | 375 +++++++++++++++++++++++++++++++++++
1 file changed, 375 insertions(+)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index fb58c0ee7a..0d63731b56 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -327,6 +327,19 @@ static const struct exception
0xba, 0xba, 0xba, 0xba, 0xba, /* mov $0xbabababa, %edx */
0xcd, 0x2d, 0xc3 }, /* int $0x2d; ret */
17, 0, FALSE, STATUS_BREAKPOINT, 3, { 0xb8b8b8b8, 0xb9b9b9b9, 0xbabababa } },
+
+ /* test UMIP-covered instructions storing to a NULL pointer */
+ { { 0x31, 0xc0, 0x0f, 0x01, 0x00, 0xc3 }, /* xor %eax,%eax; sgdt (%eax); ret */
+ 2, 3, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0 } },
+/* 45 */
+ { { 0x31, 0xc0, 0x0f, 0x01, 0x08, 0xc3 }, /* xor %eax,%eax; sidt (%eax); ret */
+ 2, 3, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0 } },
+ { { 0x31, 0xc0, 0x0f, 0x00, 0x00, 0xc3 }, /* xor %eax,%eax; sldt (%eax); ret */
+ 2, 3, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0 } },
+ { { 0x31, 0xc0, 0x0f, 0x01, 0x20, 0xc3 }, /* xor %eax,%eax; smsw (%eax); ret */
+ 2, 3, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0 } },
+ { { 0x31, 0xc0, 0x0f, 0x00, 0x08, 0xc3 }, /* xor %eax,%eax; str (%eax); ret */
+ 2, 3, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0 } },
};
static int got_exception;
@@ -2420,6 +2433,19 @@ static const struct exception
1, 1, STATUS_SINGLE_STEP, 0 },
{ { 0xcd, 0x2c, 0xc3 },
0, 2, STATUS_ASSERTION_FAILURE, 0 },
+
+ /* test UMIP-covered instructions storing to a NULL pointer */
+ { { 0x48, 0x31, 0xc0, 0x0f, 0x01, 0x00, 0xc3 }, /* xor %rax,%rax; sgdt (%rax); ret */
+ 3, 3, STATUS_ACCESS_VIOLATION, 2, { 1, 0 } },
+ { { 0x48, 0x31, 0xc0, 0x0f, 0x01, 0x08, 0xc3 }, /* xor %rax,%rax; sidt (%rax); ret */
+ 3, 3, STATUS_ACCESS_VIOLATION, 2, { 1, 0 } },
+/* 40 */
+ { { 0x48, 0x31, 0xc0, 0x0f, 0x00, 0x00, 0xc3 }, /* xor %rax,%rax; sldt (%rax); ret */
+ 3, 3, STATUS_ACCESS_VIOLATION, 2, { 1, 0 } },
+ { { 0x48, 0x31, 0xc0, 0x0f, 0x01, 0x20, 0xc3 }, /* xor %rax,%rax; smsw (%rax); ret */
+ 3, 3, STATUS_ACCESS_VIOLATION, 2, { 1, 0 } },
+ { { 0x48, 0x31, 0xc0, 0x0f, 0x00, 0x08, 0xc3 }, /* xor %rax,%rax; str (%rax); ret */
+ 3, 3, STATUS_ACCESS_VIOLATION, 2, { 1, 0 } },
};
static int got_exception;
@@ -3383,6 +3409,353 @@ static void test_unload_trace(void)
ok(found, "Unloaded module wasn't found.\n");
}
+#if defined(__x86_64__)
+static DWORD WINAPI umip_handler( EXCEPTION_RECORD *rec, ULONG64 frame,
+ CONTEXT *context, DISPATCHER_CONTEXT *dispatcher )
+{
+ const UINT *umip_insn_len = *(const UINT **)(dispatcher->HandlerData);
+
+ got_exception++;
+ trace( "umip_handler exception: %x flags:%x addr:%p\n",
+ rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
+
+ context->Rip += *umip_insn_len;
+ return ExceptionContinueExecution;
+}
+#else
+static DWORD umip_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
+ CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
+{
+ const UINT *umip_insn_len = *(const UINT **)(frame + 1);
+
+ got_exception++;
+ trace( "umip_handler exception: %x flags:%x addr:%p\n",
+ rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
+
+ context->Eip += *umip_insn_len;
+ return ExceptionContinueExecution;
+}
+#endif
+
+/* Each UMIP test is run first using run_exception_test() in case it throws an exception. If it doesn't, the
+ * test is run again to check the returned value.
+ * Tests writing to memory have two versions: one used for run_exception_test() that writes to the stack, and the
+ * other writing to a pointer passed as an argument.
+ */
+static void umip_test_reg_mem_16(const char *insn_name,
+ const BYTE *reg16_code, UINT reg16_code_size, UINT reg16_insn_len,
+ const BYTE *reg32_code, UINT reg32_code_size, UINT reg32_insn_len,
+ const BYTE *reg64_code, UINT reg64_code_size, UINT reg64_insn_len,
+ const BYTE *mem16_arg_code, UINT mem16_arg_code_size,
+ const BYTE *mem16_stack_code, UINT mem16_stack_code_size, UINT mem16_stack_insn_len)
+{
+ /* sldt, str, smsw all store a 16-bit value to a register or memory.
+ * When the destination is a register, the 16-bit value is zero-extended to the destination register size.
+ * When the destination is memory, only the 16-bit value is stored.
+ */
+ UINT16 value16;
+ UINT32 value32;
+
+ UINT16 (*reg16_func)(void) = code_mem;
+ UINT32 (*reg32_func)(void) = code_mem;
+ void (*mem16_func)(UINT16 *value) = code_mem;
+
+ /* Destination is 16-bit register */
+ got_exception = 0;
+ run_exception_test(umip_handler, ®16_insn_len, reg16_code, reg16_code_size, 0);
+ ok(!got_exception, "%s reg16 caused exception\n", insn_name);
+ if (!got_exception)
+ {
+ memset(&value16, 0xcc, sizeof(value16));
+ memcpy(code_mem, reg16_code, reg16_code_size);
+ value16 = reg16_func();
+ trace("%s reg16: 0x%x\n", insn_name, value16);
+ }
+
+ /* Destination is 32-bit register. */
+ got_exception = 0;
+ run_exception_test(umip_handler, ®32_insn_len, reg32_code, reg32_code_size, 0);
+ ok(!got_exception, "%s reg32 caused exception\n", insn_name);
+ if (!got_exception)
+ {
+ memset(&value32, 0xcc, sizeof(value32));
+ memcpy(code_mem, reg32_code, reg32_code_size);
+ value32 = reg32_func();
+ trace("%s reg32: 0x%x\n", insn_name, value32);
+#if defined(__x86_64__)
+ /* For sldt/str in 64-bit mode, the upper 16 bits is defined to be zero */
+ if (!strcmp(insn_name, "sldt") || !strcmp(insn_name, "str"))
+ ok(value32 >> 16 == 0, "%s expected upper 16 bits = 0, got 0x%x\n", insn_name, value32 >> 16);
+#endif
+ }
+
+#if defined(__x86_64__)
+ /* Destination is 64-bit register */
+ got_exception = 0;
+ run_exception_test(umip_handler, ®64_insn_len, reg64_code, reg64_code_size, 0);
+ ok(!got_exception, "%s reg64 caused exception\n", insn_name);
+ if (!got_exception)
+ {
+ UINT64 value64;
+ UINT64 (*reg64_func)(void) = code_mem;
+
+ memset(&value64, 0xcc, sizeof(value64));
+ memcpy(code_mem, reg64_code, reg64_code_size);
+ value64 = reg64_func();
+ trace("%s reg64: 0x%llx\n", insn_name, value64);
+
+ /* For sldt/str the upper 48 bits is defined to be zero */
+ if (!strcmp(insn_name, "sldt") || !strcmp(insn_name, "str"))
+ ok(value64 >> 16 == 0, "%s expected upper 48 bits = 0, got 0x%llx\n", insn_name, value64 >> 16);
+ }
+#endif
+
+ /* Destination is memory (only the low 16 bits are defined to be written) */
+ got_exception = 0;
+ run_exception_test(umip_handler, &mem16_stack_insn_len, mem16_stack_code, mem16_stack_code_size, 0);
+ ok(!got_exception, "%s mem16_stack caused exception\n", insn_name);
+ if (!got_exception)
+ {
+ memset(&value32, 0xcc, sizeof(value32));
+ memcpy(code_mem, mem16_arg_code, mem16_arg_code_size);
+ mem16_func((UINT16 *)&value32);
+ trace("%s mem: 0x%x\n", insn_name, value32);
+ ok(value32 >> 16 == 0xcccc, "%s expected upper 16 bits = 0xcccc, got 0x%x\n", insn_name, value32 >> 16);
+ }
+}
+
+static void umip_test_mem_descriptor(const char *insn_name,
+ const BYTE *code_arg, UINT code_arg_size,
+ const BYTE *code_stack, UINT code_stack_size, UINT code_stack_insn_len)
+{
+ /* sgdt and sidt write the descriptor table register to memory.
+ * The descriptor consists of a 2-byte limit field, and a base field which
+ * is 4 bytes in 32-bit mode and 8 bytes in 64-bit mode.
+ */
+ BYTE descriptor[10];
+ void (*func)(BYTE *value) = code_mem;
+
+ got_exception = 0;
+ run_exception_test(umip_handler, &code_stack_insn_len, code_stack, code_stack_size, 0);
+ ok(!got_exception, "%s caused exception\n", insn_name);
+ if (!got_exception)
+ {
+ memset(descriptor, 0xcc, sizeof(descriptor));
+ memcpy(code_mem, code_arg, code_arg_size);
+ func(descriptor);
+ trace("%s limit: 0x%x\n", insn_name, *(UINT16 *)&descriptor[0]);
+ trace("%s base: 0x%p\n", insn_name, (void *) *(UINT_PTR *)&descriptor[2]);
+ }
+}
+
+static void umip_test_sldt(void)
+{
+ static const BYTE reg16[] = {
+ 0x66, 0x0f, 0x00, 0xc0, /* sldtw %ax */
+ 0xc3, /* ret */
+ };
+ static const BYTE reg32[] = {
+ 0x0f, 0x00, 0xc0, /* sldtl %eax */
+ 0xc3, /* ret */
+ };
+ static const BYTE reg64[] = {
+ 0x48, 0x0f, 0x00, 0xc0, /* sldtq %rax */
+ 0xc3, /* ret */
+ };
+#if defined(__x86_64__)
+ static const BYTE mem16_arg[] = {
+ 0x0f, 0x00, 0x01, /* sldtw (%rcx) */
+ 0xc3, /* ret */
+ };
+ static const BYTE mem16_stack[] = {
+ 0x0f, 0x00, 0x44, 0x24, 0x08, /* sldtw 0x8(%rsp) */
+ 0xc3, /* ret */
+ };
+#else
+ static const BYTE mem16_arg[] = {
+ 0x8b, 0x4c, 0x24, 0x04, /* movl 0x4(%esp), %ecx */
+ 0x0f, 0x00, 0x01, /* sldtw (%ecx) */
+ 0xc3, /* ret */
+ };
+ static const BYTE mem16_stack[] = {
+ 0x83, 0xec, 0x02, /* subl $0x2,%esp */
+ 0x0f, 0x00, 0x04, 0x24, /* sldtw (%esp) */
+ 0x90, /* nop (padding so mem16_stack_insn_len is same for x86_64 and i386) */
+ 0x83, 0xc4, 0x02, /* addl $0x2,%esp */
+ 0xc3, /* ret */
+ };
+#endif
+
+ umip_test_reg_mem_16("sldt",
+ reg16, sizeof(reg16), 4,
+ reg32, sizeof(reg32), 3,
+ reg64, sizeof(reg64), 4,
+ mem16_arg, sizeof(mem16_arg),
+ mem16_stack, sizeof(mem16_stack), 5);
+}
+
+static void umip_test_str(void)
+{
+ static const BYTE reg16[] = {
+ 0x66, 0x0f, 0x00, 0xc8, /* strw %ax */
+ 0xc3, /* ret */
+ };
+ static const BYTE reg32[] = {
+ 0x0f, 0x00, 0xc8, /* strl %eax */
+ 0xc3, /* ret */
+ };
+ static const BYTE reg64[] = {
+ 0x48, 0x0f, 0x00, 0xc8, /* strq %rax */
+ 0xc3, /* ret */
+ };
+#if defined(__x86_64__)
+ static const BYTE mem16_arg[] = {
+ 0x0f, 0x00, 0x09, /* strw (%rcx) */
+ 0xc3, /* ret */
+ };
+ static const BYTE mem16_stack[] = {
+ 0x0f, 0x00, 0x4c, 0x24, 0x08, /* strw 0x8(%rsp) */
+ 0xc3, /* ret */
+ };
+#else
+ static const BYTE mem16_arg[] = {
+ 0x8b, 0x4c, 0x24, 0x04, /* movl 0x4(%esp), %ecx */
+ 0x0f, 0x00, 0x09, /* strw (%ecx) */
+ 0xc3, /* ret */
+ };
+ static const BYTE mem16_stack[] = {
+ 0x83, 0xec, 0x02, /* subl $0x2,%esp */
+ 0x0f, 0x00, 0x0c, 0x24, /* strw (%esp) */
+ 0x90, /* nop (padding so mem16_stack_insn_len is same for x86_64 and i386) */
+ 0x83, 0xc4, 0x02, /* addl $0x2,%esp */
+ 0xc3, /* ret */
+ };
+#endif
+
+ umip_test_reg_mem_16("str",
+ reg16, sizeof(reg16), 4,
+ reg32, sizeof(reg32), 3,
+ reg64, sizeof(reg64), 4,
+ mem16_arg, sizeof(mem16_arg),
+ mem16_stack, sizeof(mem16_stack), 5);
+}
+
+static void umip_test_sgdt(void)
+{
+ /* sgdt destination must be memory */
+#if defined(__x86_64__)
+ static const BYTE mem_arg[] = {
+ 0x0f, 0x01, 0x01, /* sgdtt (%rcx) */
+ 0xc3, /* ret */
+ };
+ static const BYTE mem_stack[] = {
+ 0x0f, 0x01, 0x44, 0x24, 0x08, /* sgdtt 0x8(%rsp) */
+ 0xc3, /* ret */
+ };
+#else
+ static const BYTE mem_arg[] = {
+ 0x8b, 0x4c, 0x24, 0x04, /* movl 0x4(%esp), %ecx */
+ 0x0f, 0x01, 0x01, /* sgdt (%ecx) */
+ 0xc3, /* ret */
+ };
+ static const BYTE mem_stack[] = {
+ 0x83, 0xec, 0x06, /* subl $0x6,%esp */
+ 0x0f, 0x01, 0x04, 0x24, /* sgdt (%esp) */
+ 0x90, /* nop (padding so mem16_stack_insn_len is same for x86_64 and i386) */
+ 0x83, 0xc4, 0x06, /* addl $0x6,%esp */
+ 0xc3, /* ret */
+ };
+#endif
+
+ umip_test_mem_descriptor("sgdt", mem_arg, sizeof(mem_arg), mem_stack, sizeof(mem_stack), 5);
+}
+
+static void umip_test_sidt(void)
+{
+ /* sidt destination must be memory */
+#if defined(__x86_64__)
+ static const BYTE mem_arg[] = {
+ 0x0f, 0x01, 0x09, /* sidtt (%rcx) */
+ 0xc3, /* ret */
+ };
+ static const BYTE mem_stack[] = {
+ 0x0f, 0x01, 0x4c, 0x24, 0x08, /* sidtt 0x8(%rsp) */
+ 0xc3, /* ret */
+ };
+#else
+ static const BYTE mem_arg[] = {
+ 0x8b, 0x4c, 0x24, 0x04, /* movl 0x4(%esp), %ecx */
+ 0x0f, 0x01, 0x09, /* sidt (%ecx) */
+ 0xc3, /* ret */
+ };
+ static const BYTE mem_stack[] = {
+ 0x83, 0xec, 0x06, /* subl $0x6,%esp */
+ 0x0f, 0x01, 0x0c, 0x24, /* sidt (%esp) */
+ 0x90, /* nop (padding so mem16_stack_insn_len is same for x86_64 and i386) */
+ 0x83, 0xc4, 0x06, /* addl $0x6,%esp */
+ 0xc3, /* ret */
+ };
+#endif
+
+ umip_test_mem_descriptor("sidt", mem_arg, sizeof(mem_arg), mem_stack, sizeof(mem_stack), 5);
+}
+
+static void umip_test_smsw(void)
+{
+ static const BYTE reg16[] = {
+ 0x66, 0x0f, 0x01, 0xe0, /* smsww %ax */
+ 0xc3, /* ret */
+ };
+ static const BYTE reg32[] = {
+ 0x0f, 0x01, 0xe0, /* smswl %eax */
+ 0xc3, /* ret */
+ };
+ static const BYTE reg64[] = {
+ 0x48, 0x0f, 0x01, 0xe0, /* smswq %rax */
+ 0xc3, /* ret */
+ };
+
+#if defined(__x86_64__)
+ static const BYTE mem16_arg[] = {
+ 0x0f, 0x01, 0x21, /* smsww (%rcx) */
+ 0xc3, /* ret */
+ };
+ static const BYTE mem16_stack[] = {
+ 0x0f, 0x01, 0x64, 0x24, 0x08, /* smsww 0x8(%rsp) */
+ 0xc3, /* ret */
+ };
+#else
+ static const BYTE mem16_arg[] = {
+ 0x8b, 0x4c, 0x24, 0x04, /* movl 0x4(%esp), %ecx */
+ 0x0f, 0x01, 0x21, /* smsww (%ecx) */
+ 0xc3, /* ret */
+ };
+ static const BYTE mem16_stack[] = {
+ 0x83, 0xec, 0x02, /* subl $0x2,%esp */
+ 0x0f, 0x01, 0x24, 0x24, /* smsww (%esp) */
+ 0x90, /* nop (padding so mem16_stack_insn_len is same for x86_64 and i386) */
+ 0x83, 0xc4, 0x02, /* addl $0x2,%esp */
+ 0xc3, /* ret */
+ };
+#endif
+
+ umip_test_reg_mem_16("smsw",
+ reg16, sizeof(reg16), 4,
+ reg32, sizeof(reg32), 3,
+ reg64, sizeof(reg64), 4,
+ mem16_arg, sizeof(mem16_arg),
+ mem16_stack, sizeof(mem16_stack), 5);
+}
+
+static void test_umip(void)
+{
+ umip_test_sldt();
+ umip_test_str();
+ umip_test_sgdt();
+ umip_test_sidt();
+ umip_test_smsw();
+}
+
START_TEST(exception)
{
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
@@ -3513,6 +3886,7 @@ START_TEST(exception)
test_suspend_thread();
test_suspend_process();
test_unload_trace();
+ test_umip();
#elif defined(__x86_64__)
@@ -3551,6 +3925,7 @@ START_TEST(exception)
test_suspend_thread();
test_suspend_process();
test_unload_trace();
+ test_umip();
if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
test_dynamic_unwind();
--
2.23.0
Dec. 4, 2019
[PATCH v4 1/2] ntdll: Add emulation for UMIP instructions.
by Brendan Shanks
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47571
Signed-off-by: Brendan Shanks <bshanks(a)codeweavers.com>
---
dlls/ntdll/signal_i386.c | 311 +++++++++++++++++++++++++++++++-
dlls/ntdll/signal_x86_64.c | 350 ++++++++++++++++++++++++++++++++++++-
2 files changed, 645 insertions(+), 16 deletions(-)
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index e9dd0de2fc..dc30fc3ad2 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -1521,37 +1521,302 @@ __ASM_STDCALL_FUNC( NtGetContextThread, 8,
__ASM_CFI(".cfi_same_value %ebp\n\t")
"ret $8" )
+/***********************************************************************
+ * User-Mode Instruction Prevention (UMIP) is an x86 feature that prevents user-space
+ * code (CPL > 0) from executing the sgdt, sidt, sldt, smsw, and str instructions.
+ * If one of these instructions is executed, a general protection fault is issued.
+ *
+ * UMIP was first implemented by the AMD Zen2 and Intel Sunny Cove microarchitectures
+ * (both released in 2019).
+ *
+ * On Linux:
+ * The kernel traps the GPF and emulates sgdt, sidt, and smsw.
+ * sldt and str are not emulated.
+ *
+ * When the kernel doesn't emulate an instruction, the process receives a SIGSEGV.
+ * emulate_umip_instr() emulates all instructions not emulated by the Linux kernel.
+ */
+
+/* Dummy LDT, matches what I see on Windows and Linux */
+#define UMIP_DUMMY_LDT 0
+
+/* Dummy task register, matches what I see on Windows and Linux */
+#define UMIP_DUMMY_TR 0x40
+
+static void *get_reg_address( CONTEXT *context, BYTE rm )
+{
+ switch (rm & 7)
+ {
+ case 0: return &context->Eax;
+ case 1: return &context->Ecx;
+ case 2: return &context->Edx;
+ case 3: return &context->Ebx;
+ case 4: return &context->Esp;
+ case 5: return &context->Ebp;
+ case 6: return &context->Esi;
+ case 7: return &context->Edi;
+ }
+ return NULL;
+}
+
+/***********************************************************************
+ * INSTR_GetOperandAddr
+ *
+ * Return the address of an instruction operand (from the mod/rm byte).
+ */
+static int INSTR_GetOperandAddr( CONTEXT *context, BYTE *instr, unsigned int instr_len,
+ int long_addr, int segprefix, int *len, void **addr )
+{
+ int mod, rm, base = 0, index = 0, ss = 0, off;
+ unsigned int i = 0;
+
+#define GET_VAL( val, type ) \
+ { if (sizeof(type) > (instr_len - i)) return 0; \
+ *val = *(type *)&instr[i]; i += sizeof(type); *len += sizeof(type); }
+
+ *len = 0;
+ GET_VAL( &mod, BYTE );
+ rm = mod & 7;
+ mod >>= 6;
+
+ if (mod == 3)
+ {
+ *addr = get_reg_address( context, rm );
+ return 1;
+ }
+
+ if (long_addr)
+ {
+ if (rm == 4)
+ {
+ BYTE sib;
+ GET_VAL( &sib, BYTE );
+ rm = sib & 7;
+ ss = sib >> 6;
+ switch((sib >> 3) & 7)
+ {
+ case 0: index = context->Eax; break;
+ case 1: index = context->Ecx; break;
+ case 2: index = context->Edx; break;
+ case 3: index = context->Ebx; break;
+ case 4: index = 0; break;
+ case 5: index = context->Ebp; break;
+ case 6: index = context->Esi; break;
+ case 7: index = context->Edi; break;
+ }
+ }
+
+ switch(rm)
+ {
+ case 0: base = context->Eax; break;
+ case 1: base = context->Ecx; break;
+ case 2: base = context->Edx; break;
+ case 3: base = context->Ebx; break;
+ case 4: base = context->Esp; break;
+ case 5: base = context->Ebp; break;
+ case 6: base = context->Esi; break;
+ case 7: base = context->Edi; break;
+ }
+ switch (mod)
+ {
+ case 0:
+ if (rm == 5) /* special case: ds:(disp32) */
+ {
+ GET_VAL( &base, DWORD );
+ }
+ break;
+
+ case 1: /* 8-bit disp */
+ GET_VAL( &off, BYTE );
+ base += (signed char)off;
+ break;
+
+ case 2: /* 32-bit disp */
+ GET_VAL( &off, DWORD );
+ base += (signed long)off;
+ break;
+ }
+ }
+ else /* short address */
+ {
+ switch(rm)
+ {
+ case 0: /* ds:(bx,si) */
+ base = LOWORD(context->Ebx) + LOWORD(context->Esi);
+ break;
+ case 1: /* ds:(bx,di) */
+ base = LOWORD(context->Ebx) + LOWORD(context->Edi);
+ break;
+ case 2: /* ss:(bp,si) */
+ base = LOWORD(context->Ebp) + LOWORD(context->Esi);
+ break;
+ case 3: /* ss:(bp,di) */
+ base = LOWORD(context->Ebp) + LOWORD(context->Edi);
+ break;
+ case 4: /* ds:(si) */
+ base = LOWORD(context->Esi);
+ break;
+ case 5: /* ds:(di) */
+ base = LOWORD(context->Edi);
+ break;
+ case 6: /* ss:(bp) */
+ base = LOWORD(context->Ebp);
+ break;
+ case 7: /* ds:(bx) */
+ base = LOWORD(context->Ebx);
+ break;
+ }
+
+ switch(mod)
+ {
+ case 0:
+ if (rm == 6) /* special case: ds:(disp16) */
+ {
+ GET_VAL( &base, WORD );
+ }
+ break;
+
+ case 1: /* 8-bit disp */
+ GET_VAL( &off, BYTE );
+ base += (signed char)off;
+ break;
+
+ case 2: /* 16-bit disp */
+ GET_VAL( &off, WORD );
+ base += (signed short)off;
+ break;
+ }
+ base &= 0xffff;
+ }
+ /* FIXME: we assume that all segments have a base of 0 */
+ *addr = (void *)(base + (index << ss));
+ return 1;
+#undef GET_VAL
+}
+
+/***********************************************************************
+ * emulate_umip_instr
+ *
+ * Emulate a UMIP-protected instruction.
+ * Returns: 0 if no instruction emulated,
+ * 1 if instruction emulated successfully,
+ * 2 if instruction's write to memory failed.
+ */
+static int emulate_umip_instr( CONTEXT *context, BYTE *instr, unsigned int len, void **err_addr,
+ int segprefix, unsigned int prefixlen, int long_op, int long_addr )
+{
+ if (len < 2) return 0;
+
+ if (instr[0] == 0x00) /* sldt/str */
+ {
+ int reg = (instr[1] >> 3) & 7;
+ switch (reg)
+ {
+ case 0: /* sldt */
+ case 1: /* str */
+ {
+ int instr_len;
+ int mod = instr[1] >> 6;
+ void *data;
+ UINT16 dummy_value;
+
+ if (!INSTR_GetOperandAddr( context, &instr[1], len - 1, long_addr,
+ segprefix, &instr_len, &data ))
+ return 0;
+
+ if (reg == 0)
+ {
+ /* sldt */
+ dummy_value = UMIP_DUMMY_LDT;
+ TRACE( "sldt at 0x%08x\n", context->Eip );
+ }
+ else
+ {
+ /* str */
+ dummy_value = UMIP_DUMMY_TR;
+ TRACE( "str at 0x%08x\n", context->Eip );
+ }
+
+ if (mod == 3)
+ {
+ /* Destination operand is a register.
+ * Zero-extend the dummy value and store to the register. */
+ UINT32 dummy_value_32 = dummy_value;
+ memcpy( data, &dummy_value_32, long_op ? 4 : 2 );
+ }
+ else
+ {
+ /* Destination operand is a memory location.
+ * Only copy 16 bits regardless of operand size. */
+ if (virtual_uninterrupted_write_memory( data, &dummy_value, sizeof(dummy_value) ))
+ {
+ TRACE( "memory write by 0x%08x to %p failed\n", context->Eip, data );
+ *err_addr = data;
+ return 2;
+ }
+ }
+ context->Eip += prefixlen + instr_len + 2;
+ return 1;
+ }
+ }
+ }
+ else if (instr[0] == 0x01) /* sgdt/sidt/str */
+ {
+ /* The Linux kernel already emulates these instructions for 32-bit processes,
+ * Wine should never get an exception for them.
+ * However, it may be necessary in the future to emulate these instructions
+ * for other OSes if they don't do any emulation.
+ */
+ }
+
+ return 0;
+}
/***********************************************************************
* is_privileged_instr
*
- * Check if the fault location is a privileged instruction.
+ * Check if the fault location is a privileged instruction, and emulate a UMIP-protected instruction if found.
* Based on the instruction emulation code in dlls/kernel/instr.c.
+ * Returns: 0 if no privileged instruction found or emulation failed,
+ * 1 if instruction found and ExceptionCode has been set,
+ * 2 if instruction was successfully emulated.
*/
-static inline DWORD is_privileged_instr( CONTEXT *context )
+static inline int is_privileged_instr( struct stack_layout *stack )
{
BYTE instr[16];
+ CONTEXT *context = &stack->context;
unsigned int i, len, prefix_count = 0;
+ int long_op = 1, long_addr = 1;
+ int segprefix = -1; /* no prefix */
if (!wine_ldt_is_system( context->SegCs )) return 0;
len = virtual_uninterrupted_read_memory( (BYTE *)context->Eip, instr, sizeof(instr) );
- for (i = 0; i < len; i++) switch (instr[i])
+ for (i = 0; i < len; i++)
+ {
+ switch (instr[i])
{
/* instruction prefixes */
case 0x2e: /* %cs: */
+ segprefix = context->SegCs; prefix_count++; break;
case 0x36: /* %ss: */
+ segprefix = context->SegSs; prefix_count++; break;
case 0x3e: /* %ds: */
+ segprefix = context->SegDs; prefix_count++; break;
case 0x26: /* %es: */
+ segprefix = context->SegEs; prefix_count++; break;
case 0x64: /* %fs: */
+ segprefix = context->SegFs; prefix_count++; break;
case 0x65: /* %gs: */
+ segprefix = context->SegGs; prefix_count++; break;
case 0x66: /* opcode size */
+ long_op = !long_op; prefix_count++; break;
case 0x67: /* addr size */
+ long_addr = !long_addr; prefix_count++; break;
case 0xf0: /* lock */
case 0xf2: /* repne */
case 0xf3: /* repe */
- if (++prefix_count >= 15) return EXCEPTION_ILLEGAL_INSTRUCTION;
- continue;
+ prefix_count++; break;
case 0x0f: /* extended instruction */
if (i == len - 1) return 0;
@@ -1561,7 +1826,28 @@ static inline DWORD is_privileged_instr( CONTEXT *context )
case 0x21: /* mov drX, reg */
case 0x22: /* mov reg, crX */
case 0x23: /* mov reg drX */
- return EXCEPTION_PRIV_INSTRUCTION;
+ stack->rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
+ return 1;
+
+ case 0x00: /* sldt/str */
+ case 0x01: /* sgdt/sidt/smsw */
+ {
+ void *err_addr;
+ int result = emulate_umip_instr( context, &instr[i+1], len - i - 1, &err_addr,
+ segprefix, prefix_count, long_op, long_addr );
+ if (result == 1)
+ return 2;
+ else if (result == 2)
+ {
+ stack->rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
+ stack->rec.NumberParameters = 2;
+ stack->rec.ExceptionInformation[0] = 1;
+ stack->rec.ExceptionInformation[1] = (ULONG_PTR)err_addr;
+ return 1;
+ }
+ else
+ return 0;
+ }
}
return 0;
case 0x6c: /* insb (%dx) */
@@ -1580,10 +1866,14 @@ static inline DWORD is_privileged_instr( CONTEXT *context )
case 0xf4: /* hlt */
case 0xfa: /* cli */
case 0xfb: /* sti */
- return EXCEPTION_PRIV_INSTRUCTION;
+ stack->rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
+ return 1;
default:
return 0;
}
+
+ if (prefix_count >= 15) { stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; return 1; }
+ }
return 0;
}
@@ -2016,7 +2306,12 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
case TRAP_x86_UNKNOWN: /* Unknown fault code */
{
WORD err = get_error_code(context);
- if (!err && (stack->rec.ExceptionCode = is_privileged_instr( &stack->context ))) break;
+ int result;
+ if (!err && (result = is_privileged_instr( stack )))
+ {
+ if (result == 1) break;
+ else { restore_context( &stack->context, sigcontext ); return; }
+ }
if ((err & 7) == 2 && handle_interrupt( err >> 3, context, stack )) return;
stack->rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
stack->rec.NumberParameters = 2;
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index c372f65b34..b496a47ae5 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -2752,25 +2752,325 @@ static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *
EFL_sig(sigcontext) &= ~(0x100|0x400|0x40000);
}
+/***********************************************************************
+ * User-Mode Instruction Prevention (UMIP) is an x86 feature that prevents user-space
+ * code (CPL > 0) from executing the sgdt, sidt, sldt, smsw, and str instructions.
+ * If one of these instructions is executed, a general protection fault is issued.
+ *
+ * UMIP was first implemented by the AMD Zen2 and Intel Sunny Cove microarchitectures
+ * (both released in 2019).
+ *
+ * On Linux:
+ * Kernel 5.4 and newer emulate sgdt, sidt, and smsw. sldt and str are not emulated.
+ * Kernels older than v5.4 do not emulate any instructions.
+ *
+ * When the kernel doesn't emulate an instruction, the process receives a SIGSEGV.
+ * emulate_umip_instr() emulates all instructions not emulated by the Linux kernel.
+ */
+
+/* Dummy base addresses are the same as used by the kernel */
+#define UMIP_DUMMY_GDT_BASE 0xfffffffffffe0000ULL
+#define UMIP_DUMMY_IDT_BASE 0xffffffffffff0000ULL
+#define UMIP_DUMMY_GDT_IDT_LIMIT 0
+
+#define UMIP_GDT_IDT_BASE_SIZE_64BIT 8
+#define UMIP_GDT_IDT_LIMIT_SIZE 2
+
+/* Dummy LDT, matches what I see on Windows and Linux */
+#define UMIP_DUMMY_LDT 0
+
+/* Dummy task register, matches what I see on Windows and Linux */
+#define UMIP_DUMMY_TR 0x40
+
+/* Dummy MSW is same value used by kernel, defined as:
+ * (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET |
+ * X86_CR0_NE | X86_CR0_WP | X86_CR0_AM |
+ * X86_CR0_PG)
+ */
+#define UMIP_DUMMY_MSW 0x33
+
+#define REX_B 1
+#define REX_X 2
+#define REX_R 4
+#define REX_W 8
+
+#define REGMODRM_MOD( regmodrm, rex ) ((regmodrm) >> 6)
+#define REGMODRM_REG( regmodrm, rex ) (((regmodrm) >> 3) & 7) | (((rex) & REX_R) ? 8 : 0)
+#define REGMODRM_RM( regmodrm, rex ) (((regmodrm) & 7) | (((rex) & REX_B) ? 8 : 0))
+
+#define SIB_SS( sib, rex ) ((sib) >> 6)
+#define SIB_INDEX( sib, rex ) (((sib) >> 3) & 7) | (((rex) & REX_X) ? 8 : 0)
+#define SIB_BASE( sib, rex ) (((sib) & 7) | (((rex) & REX_B) ? 8 : 0))
+
+static inline DWORD64 *get_int_reg_ptr( CONTEXT *context, int index )
+{
+ return &context->Rax + index; /* index should be in range 0 .. 15 */
+}
+
+static inline int get_op_size( int long_op, int rex )
+{
+ if (rex & REX_W)
+ return sizeof(DWORD64);
+ else if (long_op)
+ return sizeof(DWORD);
+ else
+ return sizeof(WORD);
+}
+
+/***********************************************************************
+ * INSTR_GetOperandAddr
+ *
+ * Return the address of an instruction operand (from the mod/rm byte).
+ */
+static int INSTR_GetOperandAddr( CONTEXT *context, BYTE *instr, unsigned int instr_len,
+ int long_addr, int rex, int segprefix, int *len, BYTE **addr )
+{
+ int mod, rm, ss = 0, off, have_sib = 0;
+ unsigned int i = 0;
+ DWORD64 base = 0, index = 0;
+
+#define GET_VAL( val, type ) \
+ { if (sizeof(type) > (instr_len - i)) return 0; \
+ *val = *(type *)&instr[i]; i += sizeof(type); *len += sizeof(type); }
+
+ *len = 0;
+ GET_VAL( &mod, BYTE );
+ rm = REGMODRM_RM( mod, rex );
+ mod = REGMODRM_MOD( mod, rex );
+
+ if (mod == 3)
+ {
+ *addr = (BYTE *)get_int_reg_ptr( context, rm );
+ return 1;
+ }
+
+ if ((rm & 7) == 4)
+ {
+ BYTE sib;
+ int id;
+
+ GET_VAL( &sib, BYTE );
+ rm = SIB_BASE( sib, rex );
+ id = SIB_INDEX( sib, rex );
+ ss = SIB_SS( sib, rex );
+
+ index = (id != 4) ? *get_int_reg_ptr( context, id ) : 0;
+ if (!long_addr) index &= 0xffffffff;
+ have_sib = 1;
+ }
+
+ base = *get_int_reg_ptr( context, rm );
+ if (!long_addr) base &= 0xffffffff;
+
+ switch (mod)
+ {
+ case 0:
+ if (rm == 5) /* special case */
+ {
+ base = have_sib ? 0 : context->Rip;
+ if (!long_addr) base &= 0xffffffff;
+ GET_VAL( &off, DWORD );
+ base += (signed long)off;
+ }
+ break;
+
+ case 1: /* 8-bit disp */
+ GET_VAL( &off, BYTE );
+ base += (signed char)off;
+ break;
+
+ case 2: /* 32-bit disp */
+ GET_VAL( &off, DWORD );
+ base += (signed long)off;
+ break;
+ }
+
+ /* FIXME: we assume that all segments have a base of 0 */
+ *addr = (BYTE *)(base + (index << ss));
+ return 1;
+#undef GET_VAL
+}
+
+/***********************************************************************
+ * emulate_umip_instr
+ *
+ * Emulate a UMIP-protected instruction.
+ * Returns: 0 if no instruction emulated,
+ * 1 if instruction emulated successfully,
+ * 2 if instruction's write to memory failed.
+ */
+static int emulate_umip_instr( CONTEXT *context, BYTE *instr, unsigned int len, void **err_addr,
+ int segprefix, unsigned int prefixlen, int long_op, int long_addr, int rex )
+{
+ if (len < 2) return 0;
+
+ if (instr[0] == 0x00) /* sldt/str */
+ {
+ int reg = REGMODRM_REG( instr[1], rex );
+ switch (reg)
+ {
+ case 0: /* sldt */
+ case 1: /* str */
+ {
+ int instr_len;
+ BYTE *data;
+ UINT16 dummy_value;
+
+ if (!INSTR_GetOperandAddr( context, &instr[1], len - 1, long_addr,
+ rex, segprefix, &instr_len, &data ))
+ return 0;
+
+ if (reg == 0)
+ {
+ /* sldt */
+ dummy_value = UMIP_DUMMY_LDT;
+ TRACE( "sldt at 0x%lx\n", context->Rip );
+ }
+ else
+ {
+ /* str */
+ dummy_value = UMIP_DUMMY_TR;
+ TRACE( "str at 0x%lx\n", context->Rip );
+ }
+
+ if (REGMODRM_MOD( instr[1], rex ) == 3)
+ {
+ /* Destination operand is a register.
+ * Zero-extend the dummy LDT and store to the register. */
+ UINT64 dummy_value_64 = dummy_value;
+ memcpy( data, &dummy_value_64, get_op_size( long_op, rex ) );
+ }
+ else
+ {
+ /* Destination operand is a memory location.
+ * Only copy 16 bits regardless of operand size. */
+ if (virtual_uninterrupted_write_memory( data, &dummy_value, sizeof(dummy_value) ))
+ {
+ TRACE( "memory write by 0x%lx to %p failed\n", context->Rip, data );
+ *err_addr = data;
+ return 2;
+ }
+ }
+ context->Rip += prefixlen + instr_len + 2;
+ return 1;
+ }
+ default: break;
+ }
+ }
+ else if (instr[0] == 0x01) /* sgdt/sidt/str */
+ {
+ int instr_len;
+ int reg = REGMODRM_REG( instr[1], rex );
+ switch (reg)
+ {
+ case 0: /* sgdt */
+ case 1: /* sidt */
+ {
+ BYTE *data;
+ UINT16 dummy_limit = UMIP_DUMMY_GDT_IDT_LIMIT;
+ UINT64 dummy_base_addr;
+
+ /* sgdt/sidt cannot use a register as the destination operand */
+ if (REGMODRM_MOD( instr[1], rex ) == 3)
+ return 0;
+
+ if (!INSTR_GetOperandAddr( context, &instr[1], len - 1, long_addr,
+ rex, segprefix, &instr_len, &data ))
+ return 0;
+
+ if (reg == 0)
+ {
+ /* sgdt */
+ dummy_base_addr = UMIP_DUMMY_GDT_BASE;
+ TRACE( "sgdt at %lx\n", context->Rip );
+ }
+ else if (reg == 1)
+ {
+ /* sidt */
+ dummy_base_addr = UMIP_DUMMY_IDT_BASE;
+ TRACE( "sidt at %lx\n", context->Rip );
+ }
+ if (virtual_uninterrupted_write_memory( data, &dummy_limit, UMIP_GDT_IDT_LIMIT_SIZE ) ||
+ virtual_uninterrupted_write_memory( data + UMIP_GDT_IDT_LIMIT_SIZE, &dummy_base_addr, UMIP_GDT_IDT_BASE_SIZE_64BIT ))
+ {
+ TRACE( "memory write by 0x%lx to %p failed\n", context->Rip, data );
+ *err_addr = data;
+ return 2;
+ }
+
+ context->Rip += prefixlen + instr_len + 2;
+ return 1;
+ }
+ case 4: /* smsw */
+ {
+ BYTE *data;
+
+ if (!INSTR_GetOperandAddr( context, &instr[1], len - 1, long_addr,
+ rex, segprefix, &instr_len, &data ))
+ return 0;
+
+ if (REGMODRM_MOD( instr[1], rex ) == 3)
+ {
+ /* Destination operand is a register.
+ * Zero-extend the dummy MSW and store to the register. */
+ UINT64 dummy_msw = UMIP_DUMMY_MSW;
+ TRACE( "smsw at %lx\n", context->Rip );
+ memcpy( data, &dummy_msw, get_op_size( long_op, rex ) );
+ }
+ else
+ {
+ /* Destination operand is a memory location.
+ * Only copy 16 bits regardless of operand size. */
+ UINT16 dummy_msw = UMIP_DUMMY_MSW;
+ TRACE( "smsw at %lx\n", context->Rip );
+ if (virtual_uninterrupted_write_memory( data, &dummy_msw, sizeof(dummy_msw) ))
+ {
+ TRACE( "memory write by 0x%lx to %p failed\n", context->Rip, data );
+ *err_addr = data;
+ return 2;
+ }
+ }
+ context->Rip += prefixlen + instr_len + 2;
+ return 1;
+ }
+ default: break;
+ }
+ }
+
+ return 0;
+}
/***********************************************************************
* is_privileged_instr
*
- * Check if the fault location is a privileged instruction.
+ * Check if the fault location is a privileged instruction, and emulate a UMIP-protected instruction if found.
+ * Returns: 0 if no privileged instruction found or emulation failed,
+ * 1 if instruction found and ExceptionCode has been set,
+ * 2 if instruction was successfully emulated.
*/
-static inline DWORD is_privileged_instr( CONTEXT *context )
+static inline int is_privileged_instr( struct stack_layout *stack )
{
BYTE instr[16];
+ CONTEXT *context = &stack->context;
+ int segprefix, long_op = 1, long_addr = 1, rex;
unsigned int i, prefix_count = 0;
unsigned int len = virtual_uninterrupted_read_memory( (BYTE *)context->Rip, instr, sizeof(instr) );
- for (i = 0; i < len; i++) switch (instr[i])
+ segprefix = -1; /* no seg prefix */
+ rex = 0; /* no rex prefix */
+ for (i = 0; i < len; i++)
+ {
+ switch (instr[i])
{
/* instruction prefixes */
case 0x2e: /* %cs: */
+ segprefix = context->SegCs; prefix_count++; break;
case 0x36: /* %ss: */
+ segprefix = context->SegSs; prefix_count++; break;
case 0x3e: /* %ds: */
+ segprefix = context->SegDs; prefix_count++; break;
case 0x26: /* %es: */
+ segprefix = context->SegEs; prefix_count++; break;
case 0x40: /* rex */
case 0x41: /* rex */
case 0x42: /* rex */
@@ -2787,15 +3087,19 @@ static inline DWORD is_privileged_instr( CONTEXT *context )
case 0x4d: /* rex */
case 0x4e: /* rex */
case 0x4f: /* rex */
+ rex = instr[i]; prefix_count++; break;
case 0x64: /* %fs: */
+ segprefix = context->SegFs; prefix_count++; break;
case 0x65: /* %gs: */
+ segprefix = context->SegGs; prefix_count++; break;
case 0x66: /* opcode size */
+ long_op = !long_op; prefix_count++; break;
case 0x67: /* addr size */
+ long_addr = !long_addr; prefix_count++; break;
case 0xf0: /* lock */
case 0xf2: /* repne */
case 0xf3: /* repe */
- if (++prefix_count >= 15) return EXCEPTION_ILLEGAL_INSTRUCTION;
- continue;
+ prefix_count++; break;
case 0x0f: /* extended instruction */
if (i == len - 1) return 0;
@@ -2808,7 +3112,28 @@ static inline DWORD is_privileged_instr( CONTEXT *context )
case 0x21: /* mov drX, reg */
case 0x22: /* mov reg, crX */
case 0x23: /* mov reg drX */
- return EXCEPTION_PRIV_INSTRUCTION;
+ stack->rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
+ return 1;
+
+ case 0x00: /* sldt/str */
+ case 0x01: /* sgdt/sidt/smsw */
+ {
+ void *err_addr;
+ int result = emulate_umip_instr( context, &instr[i+1], len - i - 1, &err_addr,
+ segprefix, prefix_count, long_op, long_addr, rex );
+ if (result == 1)
+ return 2;
+ else if (result == 2)
+ {
+ stack->rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
+ stack->rec.NumberParameters = 2;
+ stack->rec.ExceptionInformation[0] = 1;
+ stack->rec.ExceptionInformation[1] = (ULONG_PTR)err_addr;
+ return 1;
+ }
+ else
+ return 0;
+ }
}
return 0;
case 0x6c: /* insb (%dx) */
@@ -2827,10 +3152,14 @@ static inline DWORD is_privileged_instr( CONTEXT *context )
case 0xf4: /* hlt */
case 0xfa: /* cli */
case 0xfb: /* sti */
- return EXCEPTION_PRIV_INSTRUCTION;
+ stack->rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
+ return 1;
default:
return 0;
}
+
+ if (prefix_count >= 15) { stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; return 1; }
+ }
return 0;
}
@@ -2925,8 +3254,13 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
case TRAP_x86_PROTFLT: /* General protection fault */
case TRAP_x86_UNKNOWN: /* Unknown fault code */
{
+ int result;
WORD err = ERROR_sig(ucontext);
- if (!err && (stack->rec.ExceptionCode = is_privileged_instr( &stack->context ))) break;
+ if (!err && (result = is_privileged_instr( stack )))
+ {
+ if (result == 1) break;
+ else { restore_context( &stack->context, sigcontext ); return; }
+ }
if ((err & 7) == 2 && handle_interrupt( ucontext, stack )) return;
stack->rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
stack->rec.NumberParameters = 2;
--
2.23.0
Dec. 4, 2019
[PATCH v4 0/2] Add emulation for UMIP instructions
by Brendan Shanks
This patch adds emulation for instructions protected by User-Mode
Instruction Prevention (currently implemented by AMD Ryzen 3000 CPUs and
some rare Intel CPUs).
Changes from previous patch: removed CPUID checking and Linux #ifdefs
Brendan Shanks (2):
ntdll: Add emulation for UMIP instructions.
ntdll/tests: Add tests for UMIP instructions.
dlls/ntdll/signal_i386.c | 311 ++++++++++++++++++++++++++++-
dlls/ntdll/signal_x86_64.c | 350 +++++++++++++++++++++++++++++++-
dlls/ntdll/tests/exception.c | 375 +++++++++++++++++++++++++++++++++++
3 files changed, 1020 insertions(+), 16 deletions(-)
--
2.23.0
Dec. 4, 2019
[PATCH 9/9] dmime/tests: Add GetParam/SetParam tests for unsupported types
by Michael Stefaniuc
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmime/tests/dmime.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c
index a35470b4cd..e8fa6a596d 100644
--- a/dlls/dmime/tests/dmime.c
+++ b/dlls/dmime/tests/dmime.c
@@ -712,10 +712,20 @@ static void test_track(void)
else if (class[i].clsid == &CLSID_DirectMusicWaveTrack)
expect_getparam(dmt, param_types[j].type, param_types[j].name,
DMUS_E_GET_UNSUPPORTED);
- } else
+ } else {
ok(hr == DMUS_E_TYPE_UNSUPPORTED,
"IsParamSupported(%s) failed: %08x, expected DMUS_E_TYPE_UNSUPPORTED\n",
param_types[j].name, hr);
+ expect_getparam(dmt, param_types[j].type, param_types[j].name,
+ DMUS_E_GET_UNSUPPORTED);
+ if (class[i].clsid == &CLSID_DirectMusicWaveTrack)
+ expect_setparam(dmt, param_types[j].type, param_types[j].name,
+ DMUS_E_TYPE_UNSUPPORTED);
+ else
+ expect_setparam(dmt, param_types[j].type, param_types[j].name,
+ DMUS_E_SET_UNSUPPORTED);
+ }
+
/* GetParam / SetParam for IsParamSupported supported types */
if (class[i].clsid == &CLSID_DirectMusicTimeSigTrack) {
expect_getparam(dmt, &GUID_DisableTimeSig, "GUID_DisableTimeSig",
--
2.23.0
Dec. 3, 2019
[PATCH 8/9] dmime: Tempo track supports only GUID_TempoParam in GetParam()
by Michael Stefaniuc
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmime/tempotrack.c | 77 ++++++++++++++++++----------------------
dlls/dmime/tests/dmime.c | 5 +++
2 files changed, 39 insertions(+), 43 deletions(-)
diff --git a/dlls/dmime/tempotrack.c b/dlls/dmime/tempotrack.c
index 442aec37bf..94e4430b7f 100644
--- a/dlls/dmime/tempotrack.c
+++ b/dlls/dmime/tempotrack.c
@@ -153,52 +153,43 @@ static HRESULT WINAPI tempo_track_Play(IDirectMusicTrack8 *iface, void *pStateDa
return S_OK;
}
-static HRESULT WINAPI tempo_track_GetParam(IDirectMusicTrack8 *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam)
+static HRESULT WINAPI tempo_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
+ MUSIC_TIME *next, void *param)
{
- IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
-
- HRESULT hr = S_OK;
- struct list* pEntry = NULL;
- LPDMUS_PRIVATE_TEMPO_ITEM pIt = NULL;
- DMUS_TEMPO_PARAM* prm = pParam;
-
- FIXME("(%p, %s, %d, %p, %p): almost stub\n", This, debugstr_dmguid(rguidType), mtTime, pmtNext, pParam);
-
- if (NULL == pParam) {
- return E_POINTER;
- }
+ IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
+ DMUS_PRIVATE_TEMPO_ITEM *item = NULL;
+ DMUS_TEMPO_PARAM *prm = param;
+
+ TRACE("(%p, %s, %d, %p, %p)\n", This, debugstr_dmguid(type), time, next, param);
+
+ if (!param)
+ return E_POINTER;
+ if (!IsEqualGUID(type, &GUID_TempoParam))
+ return DMUS_E_GET_UNSUPPORTED;
+
+ FIXME("Partial support for GUID_TempoParam\n");
+
+ if (next)
+ *next = 0;
+ prm->mtTime = 0;
+ prm->dblTempo = 0.123456;
+
+ LIST_FOR_EACH_ENTRY(item, &This->Items, DMUS_PRIVATE_TEMPO_ITEM, entry) {
+ if (item->item.lTime <= time) {
+ MUSIC_TIME ofs = item->item.lTime - time;
+ if (ofs > prm->mtTime) {
+ prm->mtTime = ofs;
+ prm->dblTempo = item->item.dblTempo;
+ }
+ if (next && item->item.lTime > time && item->item.lTime < *next)
+ *next = item->item.lTime;
+ }
+ }
- hr = IDirectMusicTrack_IsParamSupported (iface, rguidType);
- if (FAILED(hr)) {
- return hr;
- }
+ if (0.123456 == prm->dblTempo)
+ return DMUS_E_NOT_FOUND;
- if (NULL != pmtNext) *pmtNext = 0;
- prm->mtTime = 0;
- prm->dblTempo = 0.123456;
-
- LIST_FOR_EACH (pEntry, &This->Items) {
- pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_TEMPO_ITEM, entry);
- /*TRACE(" - %p -> 0x%lx,%p\n", pIt, pIt->item.lTime, pIt->item.dblTempo);*/
- if (pIt->item.lTime <= mtTime) {
- MUSIC_TIME ofs = pIt->item.lTime - mtTime;
- if (ofs > prm->mtTime) {
- prm->mtTime = ofs;
- prm->dblTempo = pIt->item.dblTempo;
- }
- if (NULL != pmtNext && pIt->item.lTime > mtTime) {
- if (pIt->item.lTime < *pmtNext) {
- *pmtNext = pIt->item.lTime;
- }
- }
- }
- }
-
- if (0.123456 == prm->dblTempo) {
- return DMUS_E_NOT_FOUND;
- }
- return S_OK;
+ return S_OK;
}
static HRESULT WINAPI tempo_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c
index 3e25328cd8..a35470b4cd 100644
--- a/dlls/dmime/tests/dmime.c
+++ b/dlls/dmime/tests/dmime.c
@@ -724,6 +724,11 @@ static void test_track(void)
DMUS_E_GET_UNSUPPORTED);
expect_setparam(dmt, &GUID_TimeSignature, "GUID_TimeSignature",
DMUS_E_SET_UNSUPPORTED);
+ } else if (class[i].clsid == &CLSID_DirectMusicTempoTrack) {
+ expect_getparam(dmt, &GUID_DisableTempo, "GUID_DisableTempo",
+ DMUS_E_GET_UNSUPPORTED);
+ expect_getparam(dmt, &GUID_EnableTempo, "GUID_EnableTempo",
+ DMUS_E_GET_UNSUPPORTED);
}
}
} else {
--
2.23.0
Dec. 3, 2019
[PATCH 7/9] dmime: Partial implementation of the Tempo track SetParam()
by Michael Stefaniuc
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmime/tempotrack.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/dlls/dmime/tempotrack.c b/dlls/dmime/tempotrack.c
index 6038f7ce9f..442aec37bf 100644
--- a/dlls/dmime/tempotrack.c
+++ b/dlls/dmime/tempotrack.c
@@ -201,12 +201,33 @@ static HRESULT WINAPI tempo_track_GetParam(IDirectMusicTrack8 *iface, REFGUID rg
return S_OK;
}
-static HRESULT WINAPI tempo_track_SetParam(IDirectMusicTrack8 *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, void *pParam)
+static HRESULT WINAPI tempo_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
+ void *param)
{
- IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
- FIXME("(%p, %s, %d, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pParam);
- return S_OK;
+ IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface);
+
+ TRACE("(%p, %s, %d, %p)\n", This, debugstr_dmguid(type), time, param);
+
+ if (IsEqualGUID(type, &GUID_DisableTempo)) {
+ if (!param)
+ return DMUS_E_TYPE_DISABLED;
+ FIXME("GUID_DisableTempo not handled yet\n");
+ return S_OK;
+ }
+ if (IsEqualGUID(type, &GUID_EnableTempo)) {
+ if (!param)
+ return DMUS_E_TYPE_DISABLED;
+ FIXME("GUID_EnableTempo not handled yet\n");
+ return S_OK;
+ }
+ if (IsEqualGUID(type, &GUID_TempoParam)) {
+ if (!param)
+ return E_POINTER;
+ FIXME("GUID_TempoParam not handled yet\n");
+ return S_OK;
+ }
+
+ return DMUS_E_SET_UNSUPPORTED;
}
static HRESULT WINAPI tempo_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID rguidType)
--
2.23.0
Dec. 3, 2019
[PATCH 6/9] dmime: Partial implementation of the TimeSig track Get/SetParam
by Michael Stefaniuc
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmime/tests/dmime.c | 9 +++++++++
dlls/dmime/timesigtrack.c | 38 ++++++++++++++++++++++++++++----------
2 files changed, 37 insertions(+), 10 deletions(-)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c
index a08fc19c22..3e25328cd8 100644
--- a/dlls/dmime/tests/dmime.c
+++ b/dlls/dmime/tests/dmime.c
@@ -716,6 +716,15 @@ static void test_track(void)
ok(hr == DMUS_E_TYPE_UNSUPPORTED,
"IsParamSupported(%s) failed: %08x, expected DMUS_E_TYPE_UNSUPPORTED\n",
param_types[j].name, hr);
+ /* GetParam / SetParam for IsParamSupported supported types */
+ if (class[i].clsid == &CLSID_DirectMusicTimeSigTrack) {
+ expect_getparam(dmt, &GUID_DisableTimeSig, "GUID_DisableTimeSig",
+ DMUS_E_GET_UNSUPPORTED);
+ expect_getparam(dmt, &GUID_EnableTimeSig, "GUID_EnableTimeSig",
+ DMUS_E_GET_UNSUPPORTED);
+ expect_setparam(dmt, &GUID_TimeSignature, "GUID_TimeSignature",
+ DMUS_E_SET_UNSUPPORTED);
+ }
}
} else {
hr = IDirectMusicTrack_GetParam(dmt, NULL, 0, NULL, NULL);
diff --git a/dlls/dmime/timesigtrack.c b/dlls/dmime/timesigtrack.c
index 74b2c3652d..697b3e3593 100644
--- a/dlls/dmime/timesigtrack.c
+++ b/dlls/dmime/timesigtrack.c
@@ -117,20 +117,38 @@ static HRESULT WINAPI IDirectMusicTrackImpl_Play(IDirectMusicTrack *iface, void
return S_OK;
}
-static HRESULT WINAPI IDirectMusicTrackImpl_GetParam(IDirectMusicTrack *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam)
+static HRESULT WINAPI IDirectMusicTrackImpl_GetParam(IDirectMusicTrack *iface, REFGUID type,
+ MUSIC_TIME time, MUSIC_TIME *next, void *param)
{
- IDirectMusicTimeSigTrack *This = impl_from_IDirectMusicTrack(iface);
- FIXME("(%p, %s, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pmtNext, pParam);
- return S_OK;
+ IDirectMusicTimeSigTrack *This = impl_from_IDirectMusicTrack(iface);
+
+ TRACE("(%p, %s, %d, %p, %p)\n", This, debugstr_dmguid(type), time, next, param);
+
+ if (IsEqualGUID(type, &GUID_TimeSignature)) {
+ FIXME("GUID_TimeSignature not handled yet\n");
+ return DMUS_E_NOT_FOUND;
+ }
+
+ return DMUS_E_GET_UNSUPPORTED;
}
-static HRESULT WINAPI IDirectMusicTrackImpl_SetParam(IDirectMusicTrack *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, void *pParam)
+static HRESULT WINAPI IDirectMusicTrackImpl_SetParam(IDirectMusicTrack *iface, REFGUID type,
+ MUSIC_TIME time, void *param)
{
- IDirectMusicTimeSigTrack *This = impl_from_IDirectMusicTrack(iface);
- FIXME("(%p, %s, %d, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pParam);
- return S_OK;
+ IDirectMusicTimeSigTrack *This = impl_from_IDirectMusicTrack(iface);
+
+ TRACE("(%p, %s, %d, %p)\n", This, debugstr_dmguid(type), time, param);
+
+ if (IsEqualGUID(type, &GUID_DisableTimeSig)) {
+ FIXME("GUID_DisableTimeSig not handled yet\n");
+ return S_OK;
+ }
+ if (IsEqualGUID(type, &GUID_EnableTimeSig)) {
+ FIXME("GUID_EnableTimeSig not handled yet\n");
+ return S_OK;
+ }
+
+ return DMUS_E_SET_UNSUPPORTED;
}
static HRESULT WINAPI IDirectMusicTrackImpl_IsParamSupported(IDirectMusicTrack *iface,
--
2.23.0
Dec. 3, 2019
[PATCH 5/9] dmime: Partial implementation of the Wave track Get/SetParam
by Michael Stefaniuc
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmime/tests/dmime.c | 3 +++
dlls/dmime/wavetrack.c | 48 +++++++++++++++++++++++++++++++---------
2 files changed, 41 insertions(+), 10 deletions(-)
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c
index 723dc88399..a08fc19c22 100644
--- a/dlls/dmime/tests/dmime.c
+++ b/dlls/dmime/tests/dmime.c
@@ -709,6 +709,9 @@ static void test_track(void)
} else if (class[i].clsid == &CLSID_DirectMusicMarkerTrack)
expect_setparam(dmt, param_types[j].type, param_types[j].name,
DMUS_E_SET_UNSUPPORTED);
+ else if (class[i].clsid == &CLSID_DirectMusicWaveTrack)
+ expect_getparam(dmt, param_types[j].type, param_types[j].name,
+ DMUS_E_GET_UNSUPPORTED);
} else
ok(hr == DMUS_E_TYPE_UNSUPPORTED,
"IsParamSupported(%s) failed: %08x, expected DMUS_E_TYPE_UNSUPPORTED\n",
diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c
index 34adca6065..1c6b08b523 100644
--- a/dlls/dmime/wavetrack.c
+++ b/dlls/dmime/wavetrack.c
@@ -120,20 +120,48 @@ static HRESULT WINAPI wave_track_Play(IDirectMusicTrack8 *iface, void *pStateDat
return S_OK;
}
-static HRESULT WINAPI wave_track_GetParam(IDirectMusicTrack8 *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam)
+static HRESULT WINAPI wave_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
+ MUSIC_TIME *next, void *param)
{
- IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface);
- FIXME("(%p, %s, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pmtNext, pParam);
- return S_OK;
+ IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface);
+
+ TRACE("(%p, %s, %d, %p, %p): not supported\n", This, debugstr_dmguid(type), time, next, param);
+ return DMUS_E_GET_UNSUPPORTED;
}
-static HRESULT WINAPI wave_track_SetParam(IDirectMusicTrack8 *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, void *pParam)
+static HRESULT WINAPI wave_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
+ void *param)
{
- IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface);
- FIXME("(%p, %s, %d, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pParam);
- return S_OK;
+ IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface);
+
+ TRACE("(%p, %s, %d, %p)\n", This, debugstr_dmguid(type), time, param);
+
+ if (IsEqualGUID(type, &GUID_Disable_Auto_Download)) {
+ FIXME("GUID_Disable_Auto_Download not handled yet\n");
+ return S_OK;
+ }
+ if (IsEqualGUID(type, &GUID_Download)) {
+ FIXME("GUID_Download not handled yet\n");
+ return S_OK;
+ }
+ if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) {
+ FIXME("GUID_DownloadToAudioPath not handled yet\n");
+ return S_OK;
+ }
+ if (IsEqualGUID(type, &GUID_Enable_Auto_Download)) {
+ FIXME("GUID_Enable_Auto_Download not handled yet\n");
+ return S_OK;
+ }
+ if (IsEqualGUID(type, &GUID_Unload)) {
+ FIXME("GUID_Unload not handled yet\n");
+ return S_OK;
+ }
+ if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) {
+ FIXME("GUID_UnloadFromAudioPath not handled yet\n");
+ return S_OK;
+ }
+
+ return DMUS_E_TYPE_UNSUPPORTED;
}
static HRESULT WINAPI wave_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID type)
--
2.23.0
Dec. 3, 2019
[PATCH 4/9] dmime: Partial implementation of the Marker track Get/SetParam
by Michael Stefaniuc
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmime/markertrack.c | 35 +++++++++++++++++++++++++----------
dlls/dmime/tests/dmime.c | 4 +++-
2 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/dlls/dmime/markertrack.c b/dlls/dmime/markertrack.c
index 32dd025ed4..f41bed668a 100644
--- a/dlls/dmime/markertrack.c
+++ b/dlls/dmime/markertrack.c
@@ -117,20 +117,35 @@ static HRESULT WINAPI IDirectMusicTrackImpl_Play(IDirectMusicTrack *iface, void
return S_OK;
}
-static HRESULT WINAPI IDirectMusicTrackImpl_GetParam(IDirectMusicTrack *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam)
+static HRESULT WINAPI IDirectMusicTrackImpl_GetParam(IDirectMusicTrack *iface, REFGUID type,
+ MUSIC_TIME time, MUSIC_TIME *next, void *param)
{
- IDirectMusicMarkerTrack *This = impl_from_IDirectMusicTrack(iface);
- FIXME("(%p, %s, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pmtNext, pParam);
- return S_OK;
+ IDirectMusicMarkerTrack *This = impl_from_IDirectMusicTrack(iface);
+
+ TRACE("(%p, %s, %d, %p, %p)\n", This, debugstr_dmguid(type), time, next, param);
+
+ if (!param)
+ return E_POINTER;
+
+ if (IsEqualGUID(type, &GUID_Play_Marker)) {
+ FIXME("GUID_Play_Marker not handled yet\n");
+ return S_FALSE;
+ }
+ if (IsEqualGUID(type, &GUID_Valid_Start_Time)) {
+ FIXME("GUID_Valid_Start_Time not handled yet\n");
+ return DMUS_E_NOT_FOUND;
+ }
+
+ return DMUS_E_GET_UNSUPPORTED;
}
-static HRESULT WINAPI IDirectMusicTrackImpl_SetParam(IDirectMusicTrack *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, void *pParam)
+static HRESULT WINAPI IDirectMusicTrackImpl_SetParam(IDirectMusicTrack *iface, REFGUID type,
+ MUSIC_TIME time, void *param)
{
- IDirectMusicMarkerTrack *This = impl_from_IDirectMusicTrack(iface);
- FIXME("(%p, %s, %d, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pParam);
- return S_OK;
+ IDirectMusicMarkerTrack *This = impl_from_IDirectMusicTrack(iface);
+
+ TRACE("(%p, %s, %d, %p): not supported\n", This, debugstr_dmguid(type), time, param);
+ return DMUS_E_SET_UNSUPPORTED;
}
static HRESULT WINAPI IDirectMusicTrackImpl_IsParamSupported(IDirectMusicTrack *iface,
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c
index 0f4c43700c..723dc88399 100644
--- a/dlls/dmime/tests/dmime.c
+++ b/dlls/dmime/tests/dmime.c
@@ -706,7 +706,9 @@ static void test_track(void)
expect_getparam(dmt, param_types[j].type, param_types[j].name,
DMUS_E_GET_UNSUPPORTED);
expect_setparam(dmt, param_types[j].type, param_types[j].name, S_OK);
- }
+ } else if (class[i].clsid == &CLSID_DirectMusicMarkerTrack)
+ expect_setparam(dmt, param_types[j].type, param_types[j].name,
+ DMUS_E_SET_UNSUPPORTED);
} else
ok(hr == DMUS_E_TYPE_UNSUPPORTED,
"IsParamSupported(%s) failed: %08x, expected DMUS_E_TYPE_UNSUPPORTED\n",
--
2.23.0
Dec. 3, 2019
[PATCH 3/9] dmime: Implement the SegTrigger track Get/SetParam
by Michael Stefaniuc
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmime/segtriggertrack.c | 23 ++++++++++++-----------
dlls/dmime/tests/dmime.c | 29 +++++++++++++++++++++++++++--
2 files changed, 39 insertions(+), 13 deletions(-)
diff --git a/dlls/dmime/segtriggertrack.c b/dlls/dmime/segtriggertrack.c
index 7e1d75aa05..d36412cfc3 100644
--- a/dlls/dmime/segtriggertrack.c
+++ b/dlls/dmime/segtriggertrack.c
@@ -134,20 +134,22 @@ static HRESULT WINAPI segment_track_Play(IDirectMusicTrack8 *iface, void *pState
return S_OK;
}
-static HRESULT WINAPI segment_track_GetParam(IDirectMusicTrack8 *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam)
+static HRESULT WINAPI segment_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type,
+ MUSIC_TIME time, MUSIC_TIME *next, void *param)
{
- IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
- FIXME("(%p, %s, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pmtNext, pParam);
- return S_OK;
+ IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
+
+ TRACE("(%p, %s, %d, %p, %p): not supported\n", This, debugstr_dmguid(type), time, next, param);
+ return DMUS_E_GET_UNSUPPORTED;
}
-static HRESULT WINAPI segment_track_SetParam(IDirectMusicTrack8 *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, void *pParam)
+static HRESULT WINAPI segment_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type,
+ MUSIC_TIME time, void *param)
{
- IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
- FIXME("(%p, %s, %d, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pParam);
- return S_OK;
+ IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
+
+ TRACE("(%p, %s, %d, %p): not supported\n", This, debugstr_dmguid(type), time, param);
+ return S_OK;
}
static HRESULT WINAPI segment_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID type)
@@ -155,7 +157,6 @@ static HRESULT WINAPI segment_track_IsParamSupported(IDirectMusicTrack8 *iface,
IDirectMusicSegTriggerTrack *This = impl_from_IDirectMusicTrack8(iface);
TRACE("(%p, %s)\n", This, debugstr_dmguid(type));
-
return S_OK;
}
diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c
index f561eb391e..0f4c43700c 100644
--- a/dlls/dmime/tests/dmime.c
+++ b/dlls/dmime/tests/dmime.c
@@ -604,6 +604,26 @@ static void test_track_identify(void)
IDirectMusicSegment8_Release(seg);
}
+static void expect_getparam(IDirectMusicTrack *track, REFGUID type, const char *name,
+ HRESULT expect)
+{
+ HRESULT hr;
+ char buf[64] = { 0 };
+
+ hr = IDirectMusicTrack8_GetParam(track, type, 0, NULL, buf);
+ ok(hr == expect, "GetParam(%s) failed: %08x, expected %08x\n", name, hr, expect);
+}
+
+static void expect_setparam(IDirectMusicTrack *track, REFGUID type, const char *name,
+ HRESULT expect)
+{
+ HRESULT hr;
+ char buf[64] = { 0 };
+
+ hr = IDirectMusicTrack8_SetParam(track, type, 0, buf);
+ ok(hr == expect, "SetParam(%s) failed: %08x, expected %08x\n", name, hr, expect);
+}
+
static void test_track(void)
{
IDirectMusicTrack *dmt;
@@ -679,10 +699,15 @@ static void test_track(void)
if (class[i].has_params != ~0) {
for (j = 0; j < ARRAY_SIZE(param_types); j++) {
hr = IDirectMusicTrack8_IsParamSupported(dmt, param_types[j].type);
- if (class[i].has_params & (1 << j))
+ if (class[i].has_params & (1 << j)) {
ok(hr == S_OK, "IsParamSupported(%s) failed: %08x, expected S_OK\n",
param_types[j].name, hr);
- else
+ if (class[i].clsid == &CLSID_DirectMusicSegmentTriggerTrack) {
+ expect_getparam(dmt, param_types[j].type, param_types[j].name,
+ DMUS_E_GET_UNSUPPORTED);
+ expect_setparam(dmt, param_types[j].type, param_types[j].name, S_OK);
+ }
+ } else
ok(hr == DMUS_E_TYPE_UNSUPPORTED,
"IsParamSupported(%s) failed: %08x, expected DMUS_E_TYPE_UNSUPPORTED\n",
param_types[j].name, hr);
--
2.23.0
Dec. 3, 2019
[PATCH 2/9] dmime: Implement the ParamControl track param methods
by Michael Stefaniuc
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmime/paramcontroltrack.c | 33 ++++++++++++++++-----------------
1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/dlls/dmime/paramcontroltrack.c b/dlls/dmime/paramcontroltrack.c
index 03d69d056c..8fb3d40332 100644
--- a/dlls/dmime/paramcontroltrack.c
+++ b/dlls/dmime/paramcontroltrack.c
@@ -118,31 +118,30 @@ static HRESULT WINAPI paramcontrol_track_Play(IDirectMusicTrack8 *iface, void *p
return S_OK;
}
-static HRESULT WINAPI paramcontrol_track_GetParam(IDirectMusicTrack8 *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam)
+static HRESULT WINAPI paramcontrol_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type,
+ MUSIC_TIME time, MUSIC_TIME *next, void *param)
{
- IDirectMusicParamControlTrack *This = impl_from_IDirectMusicTrack8(iface);
- FIXME("(%p, %s, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pmtNext, pParam);
- return S_OK;
+ IDirectMusicParamControlTrack *This = impl_from_IDirectMusicTrack8(iface);
+
+ TRACE("(%p, %s, %d, %p, %p): not supported\n", This, debugstr_dmguid(type), time, next, param);
+ return DMUS_E_GET_UNSUPPORTED;
}
-static HRESULT WINAPI paramcontrol_track_SetParam(IDirectMusicTrack8 *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, void *pParam)
+static HRESULT WINAPI paramcontrol_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type,
+ MUSIC_TIME time, void *param)
{
- IDirectMusicParamControlTrack *This = impl_from_IDirectMusicTrack8(iface);
- FIXME("(%p, %s, %d, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pParam);
- return S_OK;
+ IDirectMusicParamControlTrack *This = impl_from_IDirectMusicTrack8(iface);
+
+ TRACE("(%p, %s, %d, %p): not supported\n", This, debugstr_dmguid(type), time, param);
+ return DMUS_E_SET_UNSUPPORTED;
}
-static HRESULT WINAPI paramcontrol_track_IsParamSupported(IDirectMusicTrack8 *iface,
- REFGUID rguidType)
+static HRESULT WINAPI paramcontrol_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID type)
{
- IDirectMusicParamControlTrack *This = impl_from_IDirectMusicTrack8(iface);
+ IDirectMusicParamControlTrack *This = impl_from_IDirectMusicTrack8(iface);
- TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidType));
- /* didn't find any params */
- TRACE("param unsupported\n");
- return DMUS_E_TYPE_UNSUPPORTED;
+ TRACE("(%p, %s): param type not supported\n", This, debugstr_dmguid(type));
+ return DMUS_E_TYPE_UNSUPPORTED;
}
static HRESULT WINAPI paramcontrol_track_AddNotificationType(IDirectMusicTrack8 *iface,
--
2.23.0
Dec. 3, 2019
[PATCH 1/9] dmime: Implement the Lyrics track param methods
by Michael Stefaniuc
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmime/lyricstrack.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/dlls/dmime/lyricstrack.c b/dlls/dmime/lyricstrack.c
index 7554356ba4..49f44f52a3 100644
--- a/dlls/dmime/lyricstrack.c
+++ b/dlls/dmime/lyricstrack.c
@@ -117,30 +117,30 @@ static HRESULT WINAPI lyrics_track_Play(IDirectMusicTrack8 *iface, void *pStateD
return S_OK;
}
-static HRESULT WINAPI lyrics_track_GetParam(IDirectMusicTrack8 *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam)
+static HRESULT WINAPI lyrics_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type,
+ MUSIC_TIME time, MUSIC_TIME *next, void *param)
{
- IDirectMusicLyricsTrack *This = impl_from_IDirectMusicTrack8(iface);
- FIXME("(%p, %s, %d, %p, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pmtNext, pParam);
- return S_OK;
+ IDirectMusicLyricsTrack *This = impl_from_IDirectMusicTrack8(iface);
+
+ TRACE("(%p, %s, %d, %p, %p): not supported\n", This, debugstr_dmguid(type), time, next, param);
+ return DMUS_E_GET_UNSUPPORTED;
}
-static HRESULT WINAPI lyrics_track_SetParam(IDirectMusicTrack8 *iface, REFGUID rguidType,
- MUSIC_TIME mtTime, void *pParam)
+static HRESULT WINAPI lyrics_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type,
+ MUSIC_TIME time, void *param)
{
- IDirectMusicLyricsTrack *This = impl_from_IDirectMusicTrack8(iface);
- FIXME("(%p, %s, %d, %p): stub\n", This, debugstr_dmguid(rguidType), mtTime, pParam);
- return S_OK;
+ IDirectMusicLyricsTrack *This = impl_from_IDirectMusicTrack8(iface);
+
+ TRACE("(%p, %s, %d, %p): not supported\n", This, debugstr_dmguid(type), time, param);
+ return DMUS_E_SET_UNSUPPORTED;
}
-static HRESULT WINAPI lyrics_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID rguidType)
+static HRESULT WINAPI lyrics_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID type)
{
- IDirectMusicLyricsTrack *This = impl_from_IDirectMusicTrack8(iface);
+ IDirectMusicLyricsTrack *This = impl_from_IDirectMusicTrack8(iface);
- TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidType));
- /* didn't find any params */
- TRACE("param unsupported\n");
- return DMUS_E_TYPE_UNSUPPORTED;
+ TRACE("(%p, %s): param type not supported\n", This, debugstr_dmguid(type));
+ return DMUS_E_TYPE_UNSUPPORTED;
}
static HRESULT WINAPI lyrics_track_AddNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype)
--
2.23.0
Dec. 3, 2019
[PATCH 4/4] ucrtbase: Correct behavior of strftime formats %c %r.
by Jeff Smith
Signed-off-by: Jeff Smith <whydoubt(a)gmail.com>
---
dlls/msvcrt/time.c | 14 +++++++++++++-
dlls/ucrtbase/tests/misc.c | 8 ++++----
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/dlls/msvcrt/time.c b/dlls/msvcrt/time.c
index ef4f228554..4b8ad48c09 100644
--- a/dlls/msvcrt/time.c
+++ b/dlls/msvcrt/time.c
@@ -1234,6 +1234,18 @@ static MSVCRT_size_t strftime_impl(STRFTIME_CHAR *str, MSVCRT_size_t max,
switch(*format) {
case 'c':
+#if _MSVCR_VER>=140
+ if(time_data == &C_time_curr && !alternate)
+ {
+ static const WCHAR datetime_format[] =
+ { '%','a',' ','%','b',' ','%','e',' ','%','T',' ','%','Y',0 };
+ tmp = strftime_impl(str+ret, max-ret, datetime_format, mstm, time_data, loc);
+ if(!tmp)
+ return 0;
+ ret += tmp;
+ break;
+ }
+#endif
if(!strftime_format(str, &ret, max, mstm, time_data,
alternate ? STRFTIME_TD(time_data, date) : STRFTIME_TD(time_data, short_date)))
return 0;
@@ -1387,7 +1399,7 @@ static MSVCRT_size_t strftime_impl(STRFTIME_CHAR *str, MSVCRT_size_t max,
break;
#if _MSVCR_VER>=140
case 'r':
- if(time_data == MSVCRT_locale->locinfo->lc_time_curr)
+ if(time_data == &C_time_curr)
{
if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
goto einval_error;
diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c
index d6fdf271e0..28832e9997 100644
--- a/dlls/ucrtbase/tests/misc.c
+++ b/dlls/ucrtbase/tests/misc.c
@@ -1004,8 +1004,8 @@ static void test_strftime(void)
{"%y", "00", { 0, 0, 0, 0, 0, -1900, 0, 0, 0 }},
{"%y", "99", { 0, 0, 0, 0, 0, 8099, 0, 0, 0 }},
{"%y", "", { 0, 0, 0, 0, 0, 8100, 0, 0, 0 }},
- {"%c", "Thu Jan 1 00:00:00 1970", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }, TRUE, TRUE},
- {"%c", "Thu Feb 30 00:00:00 1970", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }, TRUE, TRUE},
+ {"%c", "Thu Jan 1 00:00:00 1970", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
+ {"%c", "Thu Feb 30 00:00:00 1970", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }},
{"%#c", "Thursday, January 01, 1970 00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
{"%#c", "Thursday, February 30, 1970 00:00:00", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }},
{"%x", "01/01/70", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
@@ -1197,8 +1197,8 @@ static void test_strftime(void)
ok(ret == 19, "ret = %d\n", ret);
ok(!strcmp(buf, "01/01/1970 00:00:00"), "buf = \"%s\", expected \"%s\"\n", buf, "01/01/1970 00:00:00");
ret = p_strftime(buf, sizeof(buf), "%r", &epoch);
- todo_wine ok(ret == 8, "ret = %d\n", ret);
- todo_wine ok(!strcmp(buf, "00:00:00"), "buf = \"%s\", expected \"%s\"\n", buf, "00:00:00");
+ ok(ret == 8, "ret = %d\n", ret);
+ ok(!strcmp(buf, "00:00:00"), "buf = \"%s\", expected \"%s\"\n", buf, "00:00:00");
p_setlocale(LC_ALL, "C");
}
--
2.23.0
Dec. 3, 2019
[PATCH 3/4] msvcrt: Create global lc_time_curr and use when possible.
by Jeff Smith
Signed-off-by: Jeff Smith <whydoubt(a)gmail.com>
---
dlls/msvcrt/locale.c | 156 ++++++++++++++++++++++++++-----------------
dlls/msvcrt/msvcrt.h | 1 +
2 files changed, 95 insertions(+), 62 deletions(-)
diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c
index 6f2a83cc7c..2a5cc7fc02 100644
--- a/dlls/msvcrt/locale.c
+++ b/dlls/msvcrt/locale.c
@@ -53,6 +53,74 @@ BOOL initial_locale = TRUE;
#define MSVCRT_LEADBYTE 0x8000
#define MSVCRT_C1_DEFINED 0x200
+static MSVCRT_wchar_t C_time_curr_wstr[43][20] =
+{
+ {'S','u','n',0}, {'M','o','n',0}, {'T','u','e',0}, {'W','e','d',0},
+ {'T','h','u',0}, {'F','r','i',0}, {'S','a','t',0},
+ {'S','u','n','d','a','y',0}, {'M','o','n','d','a','y',0},
+ {'T','u','e','s','d','a','y',0}, {'W','e','d','n','e','s','d','a','y',0},
+ {'T','h','u','r','s','d','a','y',0}, {'F','r','i','d','a','y',0},
+ {'S','a','t','u','r','d','a','y',0},
+ {'J','a','n',0}, {'F','e','b',0}, {'M','a','r',0}, {'A','p','r',0},
+ {'M','a','y',0}, {'J','u','n',0}, {'J','u','l',0}, {'A','u','g',0},
+ {'S','e','p',0}, {'O','c','t',0}, {'N','o','v',0}, {'D','e','c',0},
+ {'J','a','n','u','a','r','y',0}, {'F','e','b','r','u','a','r','y',0},
+ {'M','a','r','c','h',0}, {'A','p','r','i','l',0}, {'M','a','y',0},
+ {'J','u','n','e',0}, {'J','u','l','y',0}, {'A','u','g','u','s','t',0},
+ {'S','e','p','t','e','m','b','e','r',0}, {'O','c','t','o','b','e','r',0},
+ {'N','o','v','e','m','b','e','r',0}, {'D','e','c','e','m','b','e','r',0},
+ {'A','M',0}, {'P','M',0},
+ {'M','M','/','d','d','/','y','y',0},
+ {'d','d','d','d',',',' ','M','M','M','M',' ','d','d',',',' ','y','y','y','y',0},
+ {'H','H',':','m','m',':','s','s',0}
+};
+
+static char C_time_curr_str[43][20] =
+{
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday",
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ "January", "February", "March", "April", "May", "June", "July",
+ "August", "September", "October", "November", "December",
+ "AM", "PM", "MM/dd/yy", "dddd, MMMM dd, yyyy", "HH:mm:ss"
+};
+
+static MSVCRT_wchar_t C_time_curr_locname[] = {'e','n','-','U','S',0};
+
+MSVCRT___lc_time_data C_time_curr =
+{
+ {{C_time_curr_str[0], C_time_curr_str[1], C_time_curr_str[2], C_time_curr_str[3],
+ C_time_curr_str[4], C_time_curr_str[5], C_time_curr_str[6], C_time_curr_str[7],
+ C_time_curr_str[8], C_time_curr_str[9], C_time_curr_str[10], C_time_curr_str[11],
+ C_time_curr_str[12], C_time_curr_str[13], C_time_curr_str[14], C_time_curr_str[15],
+ C_time_curr_str[16], C_time_curr_str[17], C_time_curr_str[18], C_time_curr_str[19],
+ C_time_curr_str[20], C_time_curr_str[21], C_time_curr_str[22], C_time_curr_str[23],
+ C_time_curr_str[24], C_time_curr_str[25], C_time_curr_str[26], C_time_curr_str[27],
+ C_time_curr_str[28], C_time_curr_str[29], C_time_curr_str[30], C_time_curr_str[31],
+ C_time_curr_str[32], C_time_curr_str[33], C_time_curr_str[34], C_time_curr_str[35],
+ C_time_curr_str[36], C_time_curr_str[37], C_time_curr_str[38], C_time_curr_str[39],
+ C_time_curr_str[40], C_time_curr_str[41], C_time_curr_str[42]}},
+#if _MSVCR_VER < 110
+ MAKELCID(LANG_ENGLISH, SORT_DEFAULT),
+#endif
+ {0, 0},
+ {{C_time_curr_wstr[0], C_time_curr_wstr[1], C_time_curr_wstr[2], C_time_curr_wstr[3],
+ C_time_curr_wstr[4], C_time_curr_wstr[5], C_time_curr_wstr[6], C_time_curr_wstr[7],
+ C_time_curr_wstr[8], C_time_curr_wstr[9], C_time_curr_wstr[10], C_time_curr_wstr[11],
+ C_time_curr_wstr[12], C_time_curr_wstr[13], C_time_curr_wstr[14], C_time_curr_wstr[15],
+ C_time_curr_wstr[16], C_time_curr_wstr[17], C_time_curr_wstr[18], C_time_curr_wstr[19],
+ C_time_curr_wstr[20], C_time_curr_wstr[21], C_time_curr_wstr[22], C_time_curr_wstr[23],
+ C_time_curr_wstr[24], C_time_curr_wstr[25], C_time_curr_wstr[26], C_time_curr_wstr[27],
+ C_time_curr_wstr[28], C_time_curr_wstr[29], C_time_curr_wstr[30], C_time_curr_wstr[31],
+ C_time_curr_wstr[32], C_time_curr_wstr[33], C_time_curr_wstr[34], C_time_curr_wstr[35],
+ C_time_curr_wstr[36], C_time_curr_wstr[37], C_time_curr_wstr[38], C_time_curr_wstr[39],
+ C_time_curr_wstr[40], C_time_curr_wstr[41], C_time_curr_wstr[42]}},
+#if _MSVCR_VER >= 110
+ C_time_curr_locname,
+#endif
+ {}
+};
+
/* Friendly country strings & language names abbreviations. */
static const char * const _country_synonyms[] =
{
@@ -829,7 +897,8 @@ void free_locinfo(MSVCRT_pthreadlocinfo locinfo)
MSVCRT_free(locinfo->pclmap);
MSVCRT_free(locinfo->pcumap);
- MSVCRT_free(locinfo->lc_time_curr);
+ if(locinfo->lc_time_curr != &C_time_curr)
+ MSVCRT_free(locinfo->lc_time_curr);
MSVCRT_free(locinfo);
}
@@ -929,35 +998,21 @@ static MSVCRT___lc_time_data* create_time_data(LCID lcid)
LOCALE_SSHORTDATE, LOCALE_SLONGDATE,
LOCALE_STIMEFORMAT
};
- static const char cloc_short_date[] = "MM/dd/yy";
- static const MSVCRT_wchar_t cloc_short_dateW[] = {'M','M','/','d','d','/','y','y',0};
- static const char cloc_long_date[] = "dddd, MMMM dd, yyyy";
- static const MSVCRT_wchar_t cloc_long_dateW[] = {'d','d','d','d',',',' ','M','M','M','M',' ','d','d',',',' ','y','y','y','y',0};
- static const char cloc_time[] = "HH:mm:ss";
- static const MSVCRT_wchar_t cloc_timeW[] = {'H','H',':','m','m',':','s','s',0};
MSVCRT___lc_time_data *cur;
- const DWORD flags = lcid ? 0 : LOCALE_NOUSEROVERRIDE;
- const LCID lcid_tmp = lcid ? lcid : MAKELCID(LANG_ENGLISH, SORT_DEFAULT);
int i, ret, size;
size = sizeof(MSVCRT___lc_time_data);
for(i=0; i<ARRAY_SIZE(time_data); i++) {
- if(time_data[i]==LOCALE_SSHORTDATE && !lcid) {
- size += sizeof(cloc_short_date) + sizeof(cloc_short_dateW);
- }else if(time_data[i]==LOCALE_SLONGDATE && !lcid) {
- size += sizeof(cloc_long_date) + sizeof(cloc_long_dateW);
- }else {
- ret = GetLocaleInfoA(lcid_tmp, time_data[i]|flags, NULL, 0);
- if(!ret)
- return NULL;
- size += ret;
+ ret = GetLocaleInfoA(lcid, time_data[i], NULL, 0);
+ if(!ret)
+ return NULL;
+ size += ret;
- ret = GetLocaleInfoW(lcid_tmp, time_data[i]|flags, NULL, 0);
- if(!ret)
- return NULL;
- size += ret*sizeof(MSVCRT_wchar_t);
- }
+ ret = GetLocaleInfoW(lcid, time_data[i], NULL, 0);
+ if(!ret)
+ return NULL;
+ size += ret*sizeof(MSVCRT_wchar_t);
}
#if _MSVCR_VER >= 110
size += LCIDToLocaleName(lcid, NULL, 0, 0)*sizeof(MSVCRT_wchar_t);
@@ -970,35 +1025,12 @@ static MSVCRT___lc_time_data* create_time_data(LCID lcid)
ret = 0;
for(i=0; i<ARRAY_SIZE(time_data); i++) {
cur->str.str[i] = &cur->data[ret];
- if(time_data[i]==LOCALE_SSHORTDATE && !lcid) {
- memcpy(&cur->data[ret], cloc_short_date, sizeof(cloc_short_date));
- ret += sizeof(cloc_short_date);
- }else if(time_data[i]==LOCALE_SLONGDATE && !lcid) {
- memcpy(&cur->data[ret], cloc_long_date, sizeof(cloc_long_date));
- ret += sizeof(cloc_long_date);
- }else if(time_data[i]==LOCALE_STIMEFORMAT && !lcid) {
- memcpy(&cur->data[ret], cloc_time, sizeof(cloc_time));
- ret += sizeof(cloc_time);
- }else {
- ret += GetLocaleInfoA(lcid_tmp, time_data[i]|flags,
- &cur->data[ret], size-ret);
- }
+ ret += GetLocaleInfoA(lcid, time_data[i], &cur->data[ret], size-ret);
}
for(i=0; i<ARRAY_SIZE(time_data); i++) {
cur->wstr.wstr[i] = (MSVCRT_wchar_t*)&cur->data[ret];
- if(time_data[i]==LOCALE_SSHORTDATE && !lcid) {
- memcpy(&cur->data[ret], cloc_short_dateW, sizeof(cloc_short_dateW));
- ret += sizeof(cloc_short_dateW);
- }else if(time_data[i]==LOCALE_SLONGDATE && !lcid) {
- memcpy(&cur->data[ret], cloc_long_dateW, sizeof(cloc_long_dateW));
- ret += sizeof(cloc_long_dateW);
- }else if(time_data[i]==LOCALE_STIMEFORMAT && !lcid) {
- memcpy(&cur->data[ret], cloc_timeW, sizeof(cloc_timeW));
- ret += sizeof(cloc_timeW);
- }else {
- ret += GetLocaleInfoW(lcid_tmp, time_data[i]|flags,
- (MSVCRT_wchar_t*)&cur->data[ret], size-ret)*sizeof(MSVCRT_wchar_t);
- }
+ ret += GetLocaleInfoW(lcid, time_data[i],
+ (MSVCRT_wchar_t*)&cur->data[ret], size-ret)*sizeof(MSVCRT_wchar_t);
}
#if _MSVCR_VER >= 110
cur->locname = (MSVCRT_wchar_t*)&cur->data[ret];
@@ -1664,26 +1696,26 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
lcid[MSVCRT_LC_TIME], cp[MSVCRT_LC_TIME])) {
locinfo->lc_handle[MSVCRT_LC_TIME] = old_locinfo->lc_handle[MSVCRT_LC_TIME];
locinfo->lc_id[MSVCRT_LC_TIME].wCodePage = old_locinfo->lc_id[MSVCRT_LC_TIME].wCodePage;
- } else {
- if(lcid[MSVCRT_LC_TIME] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_TIME)) {
- if(!update_threadlocinfo_category(lcid[MSVCRT_LC_TIME],
- cp[MSVCRT_LC_TIME], locinfo, MSVCRT_LC_TIME)) {
- free_locinfo(locinfo);
- return NULL;
- }
+ } else if(lcid[MSVCRT_LC_TIME] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_TIME)) {
+ if(!update_threadlocinfo_category(lcid[MSVCRT_LC_TIME],
+ cp[MSVCRT_LC_TIME], locinfo, MSVCRT_LC_TIME)) {
+ free_locinfo(locinfo);
+ return NULL;
+ }
- if(!set_lc_locale_name(locinfo, MSVCRT_LC_TIME)) {
- free_locinfo(locinfo);
- return NULL;
- }
- } else
- locinfo->lc_category[MSVCRT_LC_TIME].locale = MSVCRT__strdup("C");
+ if(!set_lc_locale_name(locinfo, MSVCRT_LC_TIME)) {
+ free_locinfo(locinfo);
+ return NULL;
+ }
locinfo->lc_time_curr = create_time_data(lcid[MSVCRT_LC_TIME]);
if(!locinfo->lc_time_curr) {
free_locinfo(locinfo);
return NULL;
}
+ } else {
+ locinfo->lc_category[MSVCRT_LC_TIME].locale = MSVCRT__strdup("C");
+ locinfo->lc_time_curr = &C_time_curr;
}
return locinfo;
diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h
index 4a7e6f4219..cd7def3c27 100644
--- a/dlls/msvcrt/msvcrt.h
+++ b/dlls/msvcrt/msvcrt.h
@@ -305,6 +305,7 @@ extern thread_data_t *msvcrt_get_thread_data(void) DECLSPEC_HIDDEN;
LCID MSVCRT_locale_to_LCID(const char*, unsigned short*, BOOL*) DECLSPEC_HIDDEN;
extern MSVCRT__locale_t MSVCRT_locale DECLSPEC_HIDDEN;
+extern MSVCRT___lc_time_data C_time_curr DECLSPEC_HIDDEN;
extern unsigned int MSVCRT___lc_codepage;
extern int MSVCRT___lc_collate_cp;
extern WORD MSVCRT__ctype [257];
--
2.23.0
Dec. 3, 2019
[PATCH 2/4] msvcrt: Factor out code for creating lc_time_data structure.
by Jeff Smith
Signed-off-by: Jeff Smith <whydoubt(a)gmail.com>
---
dlls/msvcrt/locale.c | 167 ++++++++++++++++++++++---------------------
1 file changed, 87 insertions(+), 80 deletions(-)
diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c
index fc41f05da2..6f2a83cc7c 100644
--- a/dlls/msvcrt/locale.c
+++ b/dlls/msvcrt/locale.c
@@ -910,8 +910,7 @@ static inline BOOL category_needs_update(int cat, int user_cat,
return lcid!=locinfo->lc_handle[cat] || cp!=locinfo->lc_id[cat].wCodePage;
}
-static MSVCRT_pthreadlocinfo create_locinfo(int category,
- const char *locale, MSVCRT_pthreadlocinfo old_locinfo)
+static MSVCRT___lc_time_data* create_time_data(LCID lcid)
{
static const DWORD time_data[] = {
LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
@@ -930,11 +929,6 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
LOCALE_SSHORTDATE, LOCALE_SLONGDATE,
LOCALE_STIMEFORMAT
};
- static const char collate[] = "COLLATE=";
- static const char ctype[] = "CTYPE=";
- static const char monetary[] = "MONETARY=";
- static const char numeric[] = "NUMERIC=";
- static const char time[] = "TIME=";
static const char cloc_short_date[] = "MM/dd/yy";
static const MSVCRT_wchar_t cloc_short_dateW[] = {'M','M','/','d','d','/','y','y',0};
static const char cloc_long_date[] = "dddd, MMMM dd, yyyy";
@@ -942,8 +936,91 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
static const char cloc_time[] = "HH:mm:ss";
static const MSVCRT_wchar_t cloc_timeW[] = {'H','H',':','m','m',':','s','s',0};
+ MSVCRT___lc_time_data *cur;
+ const DWORD flags = lcid ? 0 : LOCALE_NOUSEROVERRIDE;
+ const LCID lcid_tmp = lcid ? lcid : MAKELCID(LANG_ENGLISH, SORT_DEFAULT);
+ int i, ret, size;
+
+ size = sizeof(MSVCRT___lc_time_data);
+ for(i=0; i<ARRAY_SIZE(time_data); i++) {
+ if(time_data[i]==LOCALE_SSHORTDATE && !lcid) {
+ size += sizeof(cloc_short_date) + sizeof(cloc_short_dateW);
+ }else if(time_data[i]==LOCALE_SLONGDATE && !lcid) {
+ size += sizeof(cloc_long_date) + sizeof(cloc_long_dateW);
+ }else {
+ ret = GetLocaleInfoA(lcid_tmp, time_data[i]|flags, NULL, 0);
+ if(!ret)
+ return NULL;
+ size += ret;
+
+ ret = GetLocaleInfoW(lcid_tmp, time_data[i]|flags, NULL, 0);
+ if(!ret)
+ return NULL;
+ size += ret*sizeof(MSVCRT_wchar_t);
+ }
+ }
+#if _MSVCR_VER >= 110
+ size += LCIDToLocaleName(lcid, NULL, 0, 0)*sizeof(MSVCRT_wchar_t);
+#endif
+
+ cur = MSVCRT_malloc(size);
+ if(!cur)
+ return NULL;
+
+ ret = 0;
+ for(i=0; i<ARRAY_SIZE(time_data); i++) {
+ cur->str.str[i] = &cur->data[ret];
+ if(time_data[i]==LOCALE_SSHORTDATE && !lcid) {
+ memcpy(&cur->data[ret], cloc_short_date, sizeof(cloc_short_date));
+ ret += sizeof(cloc_short_date);
+ }else if(time_data[i]==LOCALE_SLONGDATE && !lcid) {
+ memcpy(&cur->data[ret], cloc_long_date, sizeof(cloc_long_date));
+ ret += sizeof(cloc_long_date);
+ }else if(time_data[i]==LOCALE_STIMEFORMAT && !lcid) {
+ memcpy(&cur->data[ret], cloc_time, sizeof(cloc_time));
+ ret += sizeof(cloc_time);
+ }else {
+ ret += GetLocaleInfoA(lcid_tmp, time_data[i]|flags,
+ &cur->data[ret], size-ret);
+ }
+ }
+ for(i=0; i<ARRAY_SIZE(time_data); i++) {
+ cur->wstr.wstr[i] = (MSVCRT_wchar_t*)&cur->data[ret];
+ if(time_data[i]==LOCALE_SSHORTDATE && !lcid) {
+ memcpy(&cur->data[ret], cloc_short_dateW, sizeof(cloc_short_dateW));
+ ret += sizeof(cloc_short_dateW);
+ }else if(time_data[i]==LOCALE_SLONGDATE && !lcid) {
+ memcpy(&cur->data[ret], cloc_long_dateW, sizeof(cloc_long_dateW));
+ ret += sizeof(cloc_long_dateW);
+ }else if(time_data[i]==LOCALE_STIMEFORMAT && !lcid) {
+ memcpy(&cur->data[ret], cloc_timeW, sizeof(cloc_timeW));
+ ret += sizeof(cloc_timeW);
+ }else {
+ ret += GetLocaleInfoW(lcid_tmp, time_data[i]|flags,
+ (MSVCRT_wchar_t*)&cur->data[ret], size-ret)*sizeof(MSVCRT_wchar_t);
+ }
+ }
+#if _MSVCR_VER >= 110
+ cur->locname = (MSVCRT_wchar_t*)&cur->data[ret];
+ LCIDToLocaleName(lcid, cur->locname, (size-ret)/sizeof(MSVCRT_wchar_t), 0);
+#else
+ cur->lcid = lcid;
+#endif
+
+ return cur;
+}
+
+static MSVCRT_pthreadlocinfo create_locinfo(int category,
+ const char *locale, MSVCRT_pthreadlocinfo old_locinfo)
+{
+ static const char collate[] = "COLLATE=";
+ static const char ctype[] = "CTYPE=";
+ static const char monetary[] = "MONETARY=";
+ static const char numeric[] = "NUMERIC=";
+ static const char time[] = "TIME=";
+
MSVCRT_pthreadlocinfo locinfo;
- LCID lcid[6] = { 0 }, lcid_tmp;
+ LCID lcid[6] = { 0 };
unsigned short cp[6] = { 0 };
const char *locale_name[6] = { 0 };
int locale_len[6] = { 0 };
@@ -952,7 +1029,7 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
#if _MSVCR_VER >= 100
MSVCRT_wchar_t wbuf[256];
#endif
- int i, ret, size;
+ int i;
TRACE("(%d %s)\n", category, locale);
@@ -1588,8 +1665,6 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
locinfo->lc_handle[MSVCRT_LC_TIME] = old_locinfo->lc_handle[MSVCRT_LC_TIME];
locinfo->lc_id[MSVCRT_LC_TIME].wCodePage = old_locinfo->lc_id[MSVCRT_LC_TIME].wCodePage;
} else {
- DWORD flags = lcid[MSVCRT_LC_TIME] ? 0 : LOCALE_NOUSEROVERRIDE;
-
if(lcid[MSVCRT_LC_TIME] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_TIME)) {
if(!update_threadlocinfo_category(lcid[MSVCRT_LC_TIME],
cp[MSVCRT_LC_TIME], locinfo, MSVCRT_LC_TIME)) {
@@ -1604,79 +1679,11 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
} else
locinfo->lc_category[MSVCRT_LC_TIME].locale = MSVCRT__strdup("C");
- size = sizeof(MSVCRT___lc_time_data);
- lcid_tmp = lcid[MSVCRT_LC_TIME] ? lcid[MSVCRT_LC_TIME] : MAKELCID(LANG_ENGLISH, SORT_DEFAULT);
- for(i=0; i<ARRAY_SIZE(time_data); i++) {
- if(time_data[i]==LOCALE_SSHORTDATE && !lcid[MSVCRT_LC_TIME]) {
- size += sizeof(cloc_short_date) + sizeof(cloc_short_dateW);
- }else if(time_data[i]==LOCALE_SLONGDATE && !lcid[MSVCRT_LC_TIME]) {
- size += sizeof(cloc_long_date) + sizeof(cloc_long_dateW);
- }else {
- ret = GetLocaleInfoA(lcid_tmp, time_data[i]|flags, NULL, 0);
- if(!ret) {
- free_locinfo(locinfo);
- return NULL;
- }
- size += ret;
-
- ret = GetLocaleInfoW(lcid_tmp, time_data[i]|flags, NULL, 0);
- if(!ret) {
- free_locinfo(locinfo);
- return NULL;
- }
- size += ret*sizeof(MSVCRT_wchar_t);
- }
- }
-#if _MSVCR_VER >= 110
- size += LCIDToLocaleName(lcid[MSVCRT_LC_TIME], NULL, 0, 0)*sizeof(MSVCRT_wchar_t);
-#endif
-
- locinfo->lc_time_curr = MSVCRT_malloc(size);
+ locinfo->lc_time_curr = create_time_data(lcid[MSVCRT_LC_TIME]);
if(!locinfo->lc_time_curr) {
free_locinfo(locinfo);
return NULL;
}
-
- ret = 0;
- for(i=0; i<ARRAY_SIZE(time_data); i++) {
- locinfo->lc_time_curr->str.str[i] = &locinfo->lc_time_curr->data[ret];
- if(time_data[i]==LOCALE_SSHORTDATE && !lcid[MSVCRT_LC_TIME]) {
- memcpy(&locinfo->lc_time_curr->data[ret], cloc_short_date, sizeof(cloc_short_date));
- ret += sizeof(cloc_short_date);
- }else if(time_data[i]==LOCALE_SLONGDATE && !lcid[MSVCRT_LC_TIME]) {
- memcpy(&locinfo->lc_time_curr->data[ret], cloc_long_date, sizeof(cloc_long_date));
- ret += sizeof(cloc_long_date);
- }else if(time_data[i]==LOCALE_STIMEFORMAT && !lcid[MSVCRT_LC_TIME]) {
- memcpy(&locinfo->lc_time_curr->data[ret], cloc_time, sizeof(cloc_time));
- ret += sizeof(cloc_time);
- }else {
- ret += GetLocaleInfoA(lcid_tmp, time_data[i]|flags,
- &locinfo->lc_time_curr->data[ret], size-ret);
- }
- }
- for(i=0; i<ARRAY_SIZE(time_data); i++) {
- locinfo->lc_time_curr->wstr.wstr[i] = (MSVCRT_wchar_t*)&locinfo->lc_time_curr->data[ret];
- if(time_data[i]==LOCALE_SSHORTDATE && !lcid[MSVCRT_LC_TIME]) {
- memcpy(&locinfo->lc_time_curr->data[ret], cloc_short_dateW, sizeof(cloc_short_dateW));
- ret += sizeof(cloc_short_dateW);
- }else if(time_data[i]==LOCALE_SLONGDATE && !lcid[MSVCRT_LC_TIME]) {
- memcpy(&locinfo->lc_time_curr->data[ret], cloc_long_dateW, sizeof(cloc_long_dateW));
- ret += sizeof(cloc_long_dateW);
- }else if(time_data[i]==LOCALE_STIMEFORMAT && !lcid[MSVCRT_LC_TIME]) {
- memcpy(&locinfo->lc_time_curr->data[ret], cloc_timeW, sizeof(cloc_timeW));
- ret += sizeof(cloc_timeW);
- }else {
- ret += GetLocaleInfoW(lcid_tmp, time_data[i]|flags,
- (MSVCRT_wchar_t*)&locinfo->lc_time_curr->data[ret], size-ret)*sizeof(MSVCRT_wchar_t);
- }
- }
-#if _MSVCR_VER >= 110
- locinfo->lc_time_curr->locname = (MSVCRT_wchar_t*)&locinfo->lc_time_curr->data[ret];
- LCIDToLocaleName(lcid[MSVCRT_LC_TIME], locinfo->lc_time_curr->locname,
- (size-ret)/sizeof(MSVCRT_wchar_t), 0);
-#else
- locinfo->lc_time_curr->lcid = lcid[MSVCRT_LC_TIME];
-#endif
}
return locinfo;
--
2.23.0
Dec. 3, 2019
[PATCH 1/4] ucrtbase: Improve strftime special test cases for %c %r formats.
by Jeff Smith
Signed-off-by: Jeff Smith <whydoubt(a)gmail.com>
---
dlls/ucrtbase/tests/misc.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c
index 083be42f42..d6fdf271e0 100644
--- a/dlls/ucrtbase/tests/misc.c
+++ b/dlls/ucrtbase/tests/misc.c
@@ -29,6 +29,7 @@
#include <fcntl.h>
#include <time.h>
#include <direct.h>
+#include <locale.h>
#include <windef.h>
#include <winbase.h>
@@ -162,6 +163,7 @@ static int* (CDECL *p_errno)(void);
static char* (CDECL *p_asctime)(const struct tm *);
static size_t (__cdecl *p_strftime)(char *, size_t, const char *, const struct tm *);
static size_t (__cdecl *p__Strftime)(char*, size_t, const char*, const struct tm*, void*);
+static char* (__cdecl *p_setlocale)(int, const char*);
static struct tm* (__cdecl *p__gmtime32)(const __time32_t*);
static void (CDECL *p_exit)(int);
static int (CDECL *p__crt_atexit)(void (CDECL*)(void));
@@ -538,6 +540,7 @@ static BOOL init(void)
p_asctime = (void*)GetProcAddress(module, "asctime");
p_strftime = (void*)GetProcAddress(module, "strftime");
p__Strftime = (void*)GetProcAddress(module, "_Strftime");
+ p_setlocale = (void*)GetProcAddress(module, "setlocale");
p__gmtime32 = (void*)GetProcAddress(module, "_gmtime32");
p__crt_atexit = (void*)GetProcAddress(module, "_crt_atexit");
p_exit = (void*)GetProcAddress(module, "exit");
@@ -1185,6 +1188,18 @@ static void test_strftime(void)
i, j, buf, tests_yweek[i].ret[j]);
}
}
+
+ if(!p_setlocale(LC_ALL, "fr-FR")) {
+ skip("fr-FR locale not available\n");
+ return;
+ }
+ ret = p_strftime(buf, sizeof(buf), "%c", &epoch);
+ ok(ret == 19, "ret = %d\n", ret);
+ ok(!strcmp(buf, "01/01/1970 00:00:00"), "buf = \"%s\", expected \"%s\"\n", buf, "01/01/1970 00:00:00");
+ ret = p_strftime(buf, sizeof(buf), "%r", &epoch);
+ todo_wine ok(ret == 8, "ret = %d\n", ret);
+ todo_wine ok(!strcmp(buf, "00:00:00"), "buf = \"%s\", expected \"%s\"\n", buf, "00:00:00");
+ p_setlocale(LC_ALL, "C");
}
static LONG* get_failures_counter(HANDLE *map)
--
2.23.0
Dec. 3, 2019
[PATCH 5/5] wined3d: Do not download textures to WINED3D_LOCATION_BUFFER in wined3d_texture_gl_unload().
by Henri Verbeet
Since we remove any potential PBO a few lines later.
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/wined3d/texture.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index a3bbf2585d8..1c315a1dd77 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -2942,6 +2942,7 @@ static void wined3d_texture_gl_unload(struct wined3d_resource *resource)
UINT sub_count = texture_gl->t.level_count * texture_gl->t.layer_count;
struct wined3d_renderbuffer_entry *entry, *entry2;
struct wined3d_device *device = resource->device;
+ unsigned int location = resource->map_binding;
const struct wined3d_gl_info *gl_info;
struct wined3d_context *context;
UINT i;
@@ -2951,14 +2952,17 @@ static void wined3d_texture_gl_unload(struct wined3d_resource *resource)
context = context_acquire(device, NULL, 0);
gl_info = wined3d_context_gl(context)->gl_info;
+ if (location == WINED3D_LOCATION_BUFFER)
+ location = WINED3D_LOCATION_SYSMEM;
+
for (i = 0; i < sub_count; ++i)
{
struct wined3d_texture_sub_resource *sub_resource = &texture_gl->t.sub_resources[i];
if (resource->access & WINED3D_RESOURCE_ACCESS_CPU
- && wined3d_texture_load_location(&texture_gl->t, i, context, resource->map_binding))
+ && wined3d_texture_load_location(&texture_gl->t, i, context, location))
{
- wined3d_texture_invalidate_location(&texture_gl->t, i, ~resource->map_binding);
+ wined3d_texture_invalidate_location(&texture_gl->t, i, ~location);
}
else
{
--
2.11.0
Dec. 3, 2019
[PATCH 4/5] wined3d: Destroy PBOs in wined3d_texture_gl_destroy_object().
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/wined3d/adapter_gl.c | 31 +++++++++++++++++++++++++++----
dlls/wined3d/texture.c | 24 ------------------------
2 files changed, 27 insertions(+), 28 deletions(-)
diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c
index 7018c6da1d9..eb9965723a2 100644
--- a/dlls/wined3d/adapter_gl.c
+++ b/dlls/wined3d/adapter_gl.c
@@ -4765,17 +4765,39 @@ static void wined3d_texture_gl_destroy_object(void *object)
{
struct wined3d_renderbuffer_entry *entry, *entry2;
struct wined3d_texture_gl *texture_gl = object;
+ struct wined3d_context *context = NULL;
const struct wined3d_gl_info *gl_info;
- struct wined3d_context *context;
struct wined3d_device *device;
+ unsigned int sub_count, i;
+ GLuint buffer_object;
TRACE("texture_gl %p.\n", texture_gl);
+ sub_count = texture_gl->t.level_count * texture_gl->t.layer_count;
+ for (i = 0; i < sub_count; ++i)
+ {
+ if (!(buffer_object = texture_gl->t.sub_resources[i].buffer_object))
+ continue;
+
+ TRACE("Deleting buffer object %u.\n", buffer_object);
+
+ if (!context)
+ {
+ context = context_acquire(texture_gl->t.resource.device, NULL, 0);
+ gl_info = wined3d_context_gl(context)->gl_info;
+ }
+
+ GL_EXTCALL(glDeleteBuffers(1, &buffer_object));
+ }
+
if (!list_empty(&texture_gl->renderbuffers))
{
device = texture_gl->t.resource.device;
- context = context_acquire(device, NULL, 0);
- gl_info = wined3d_context_gl(context)->gl_info;
+ if (!context)
+ {
+ context = context_acquire(device, NULL, 0);
+ gl_info = wined3d_context_gl(context)->gl_info;
+ }
LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &texture_gl->renderbuffers, struct wined3d_renderbuffer_entry, entry)
{
@@ -4784,9 +4806,10 @@ static void wined3d_texture_gl_destroy_object(void *object)
gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
heap_free(entry);
}
+ }
+ if (context)
context_release(context);
- }
wined3d_texture_gl_unload_texture(texture_gl);
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 260a0486302..a3bbf2585d8 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -1118,38 +1118,14 @@ ULONG CDECL wined3d_texture_incref(struct wined3d_texture *texture)
static void wined3d_texture_destroy_object(void *object)
{
- const struct wined3d_gl_info *gl_info = NULL;
struct wined3d_texture *texture = object;
- struct wined3d_context *context = NULL;
struct wined3d_dc_info *dc_info;
unsigned int sub_count;
- GLuint buffer_object;
unsigned int i;
TRACE("texture %p.\n", texture);
sub_count = texture->level_count * texture->layer_count;
- for (i = 0; i < sub_count; ++i)
- {
- if (!(buffer_object = texture->sub_resources[i].buffer_object))
- continue;
-
- TRACE("Deleting buffer object %u.\n", buffer_object);
-
- /* We may not be able to get a context in
- * wined3d_texture_destroy_object() in general, but if a buffer object
- * was previously created we can. */
- if (!context)
- {
- context = context_acquire(texture->resource.device, NULL, 0);
- gl_info = wined3d_context_gl(context)->gl_info;
- }
-
- GL_EXTCALL(glDeleteBuffers(1, &buffer_object));
- }
-
- if (context)
- context_release(context);
if ((dc_info = texture->dc_info))
{
--
2.11.0
Dec. 3, 2019
[PATCH 3/5] wined3d: Store texture sub-resource buffer objects as uintptr_t.
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/wined3d/texture.c | 17 ++++++++++-------
dlls/wined3d/wined3d_private.h | 2 +-
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 976235bf60f..260a0486302 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -477,13 +477,15 @@ void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int su
static void wined3d_texture_remove_buffer_object(struct wined3d_texture *texture,
unsigned int sub_resource_idx, const struct wined3d_gl_info *gl_info)
{
- GLuint *buffer_object = &texture->sub_resources[sub_resource_idx].buffer_object;
+ uintptr_t *buffer_object = &texture->sub_resources[sub_resource_idx].buffer_object;
+ GLuint bo;
- GL_EXTCALL(glDeleteBuffers(1, buffer_object));
+ bo = *buffer_object;
+ GL_EXTCALL(glDeleteBuffers(1, &bo));
checkGLcall("glDeleteBuffers");
TRACE("Deleted buffer object %u for texture %p, sub-resource %u.\n",
- *buffer_object, texture, sub_resource_idx);
+ bo, texture, sub_resource_idx);
wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_BUFFER);
*buffer_object = 0;
@@ -1670,19 +1672,20 @@ static void wined3d_texture_prepare_buffer_object(struct wined3d_texture *textur
unsigned int sub_resource_idx, const struct wined3d_gl_info *gl_info)
{
struct wined3d_texture_sub_resource *sub_resource;
+ GLuint bo;
sub_resource = &texture->sub_resources[sub_resource_idx];
if (sub_resource->buffer_object)
return;
- GL_EXTCALL(glGenBuffers(1, &sub_resource->buffer_object));
- GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sub_resource->buffer_object));
+ GL_EXTCALL(glGenBuffers(1, &bo));
+ GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bo));
GL_EXTCALL(glBufferData(GL_PIXEL_UNPACK_BUFFER, sub_resource->size, NULL, GL_STREAM_DRAW));
GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
checkGLcall("Create buffer object");
- TRACE("Created buffer object %u for texture %p, sub-resource %u.\n",
- sub_resource->buffer_object, texture, sub_resource_idx);
+ sub_resource->buffer_object = bo;
+ TRACE("Created buffer object %u for texture %p, sub-resource %u.\n", bo, texture, sub_resource_idx);
}
static void wined3d_texture_force_reload(struct wined3d_texture *texture)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 67756a6bbfc..3754ed9e763 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -3563,7 +3563,7 @@ struct wined3d_texture
unsigned int map_count;
uint32_t map_flags;
DWORD locations;
- GLuint buffer_object;
+ uintptr_t buffer_object;
} *sub_resources;
};
--
2.11.0
Dec. 3, 2019
[PATCH 2/5] wined3d: Do not set depth/stencil sizes on colour formats.
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/wined3d/utils.c | 41 ++++++++++++++++++++++-------------------
dlls/wined3d/wined3d_private.h | 4 ++--
2 files changed, 24 insertions(+), 21 deletions(-)
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index ac821ce732a..453bee62565 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -151,13 +151,13 @@ static const struct wined3d_format_channels formats[] =
{WINED3DFMT_R32G32B32_TYPELESS, 32, 32, 32, 0, 0, 32, 64, 0, 12, 0, 0},
{WINED3DFMT_R16G16B16A16_TYPELESS, 16, 16, 16, 16, 0, 16, 32, 48, 8, 0, 0},
{WINED3DFMT_R32G32_TYPELESS, 32, 32, 0, 0, 0, 32, 0, 0, 8, 0, 0},
- {WINED3DFMT_R32G8X24_TYPELESS, 0, 0, 0, 0, 0, 0, 0, 0, 8, 32, 8},
+ {WINED3DFMT_R32G8X24_TYPELESS, 32, 8, 0, 0, 0, 0, 0, 0, 8, 0, 0},
{WINED3DFMT_R10G10B10A2_TYPELESS, 10, 10, 10, 2, 0, 10, 20, 30, 4, 0, 0},
{WINED3DFMT_R10G10B10X2_TYPELESS, 10, 10, 10, 0, 0, 10, 20, 0, 4, 0, 0},
{WINED3DFMT_R8G8B8A8_TYPELESS, 8, 8, 8, 8, 0, 8, 16, 24, 4, 0, 0},
{WINED3DFMT_R16G16_TYPELESS, 16, 16, 0, 0, 0, 16, 0, 0, 4, 0, 0},
{WINED3DFMT_R32_TYPELESS, 32, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0},
- {WINED3DFMT_R24G8_TYPELESS, 0, 0, 0, 0, 0, 0, 0, 0, 4, 24, 8},
+ {WINED3DFMT_R24G8_TYPELESS, 24, 8, 0, 0, 0, 0, 0, 0, 4, 0, 0},
{WINED3DFMT_R8G8_TYPELESS, 8, 8, 0, 0, 0, 8, 0, 0, 2, 0, 0},
{WINED3DFMT_R16_TYPELESS, 16, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0},
{WINED3DFMT_R8_TYPELESS, 8, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
@@ -220,9 +220,9 @@ static const struct wined3d_typed_format_info typed_formats[] =
{WINED3DFMT_R32G32_UINT, WINED3DFMT_R32G32_TYPELESS, "UU"},
{WINED3DFMT_R32G32_SINT, WINED3DFMT_R32G32_TYPELESS, "II"},
{WINED3DFMT_R32G32_FLOAT, WINED3DFMT_R32G32_TYPELESS, "FF"},
- {WINED3DFMT_R32_FLOAT_X8X24_TYPELESS, WINED3DFMT_R32G8X24_TYPELESS, "DX"},
- {WINED3DFMT_X32_TYPELESS_G8X24_UINT, WINED3DFMT_R32G8X24_TYPELESS, "XS"},
- {WINED3DFMT_D32_FLOAT_S8X24_UINT, WINED3DFMT_R32G8X24_TYPELESS, "DS"},
+ {WINED3DFMT_R32_FLOAT_X8X24_TYPELESS, WINED3DFMT_R32G8X24_TYPELESS, "FXX"},
+ {WINED3DFMT_X32_TYPELESS_G8X24_UINT, WINED3DFMT_R32G8X24_TYPELESS, "XUX"},
+ {WINED3DFMT_D32_FLOAT_S8X24_UINT, WINED3DFMT_R32G8X24_TYPELESS, "DSX"},
{WINED3DFMT_R10G10B10A2_SNORM, WINED3DFMT_R10G10B10A2_TYPELESS, "iiii"},
{WINED3DFMT_R10G10B10A2_UINT, WINED3DFMT_R10G10B10A2_TYPELESS, "UUUU"},
{WINED3DFMT_R10G10B10A2_UNORM, WINED3DFMT_R10G10B10A2_TYPELESS, "uuuu"},
@@ -242,8 +242,8 @@ static const struct wined3d_typed_format_info typed_formats[] =
{WINED3DFMT_R32_FLOAT, WINED3DFMT_R32_TYPELESS, "F"},
{WINED3DFMT_R32_UINT, WINED3DFMT_R32_TYPELESS, "U"},
{WINED3DFMT_R32_SINT, WINED3DFMT_R32_TYPELESS, "I"},
- {WINED3DFMT_R24_UNORM_X8_TYPELESS, WINED3DFMT_R24G8_TYPELESS, "DX"},
- {WINED3DFMT_X24_TYPELESS_G8_UINT, WINED3DFMT_R24G8_TYPELESS, "XS"},
+ {WINED3DFMT_R24_UNORM_X8_TYPELESS, WINED3DFMT_R24G8_TYPELESS, "uX"},
+ {WINED3DFMT_X24_TYPELESS_G8_UINT, WINED3DFMT_R24G8_TYPELESS, "XU"},
{WINED3DFMT_D24_UNORM_S8_UINT, WINED3DFMT_R24G8_TYPELESS, "DS"},
{WINED3DFMT_R8G8_SNORM, WINED3DFMT_R8G8_TYPELESS, "ii"},
{WINED3DFMT_R8G8_UNORM, WINED3DFMT_R8G8_TYPELESS, "uu"},
@@ -2099,6 +2099,12 @@ static BOOL init_format_base_info(struct wined3d_adapter *adapter)
format->depth_size = format->red_size;
format->red_size = format->red_offset = 0;
}
+
+ if (channel_type == WINED3D_CHANNEL_TYPE_STENCIL && !format->stencil_size)
+ {
+ format->stencil_size = format->green_size;
+ format->green_size = format->green_offset = 0;
+ }
}
format->component_count = component_count;
@@ -3785,27 +3791,24 @@ static BOOL init_typeless_formats(const struct wined3d_adapter *adapter)
typeless_format->flags[j] &= ~(WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
}
- if ((format_id = typeless_depth_stencil_formats[i].depth_view_id))
+ if ((format_id = typeless_depth_stencil_formats[i].depth_view_id)
+ && typeless_depth_stencil_formats[i].separate_depth_view_format)
{
if (!(depth_view_format = get_format_internal(adapter, format_id)))
return FALSE;
- if (typeless_depth_stencil_formats[i].separate_depth_view_format)
- {
- copy_format(adapter, depth_view_format, ds_format);
- depth_view_format->stencil_size = 0;
- }
- else
- {
- depth_view_format->depth_size = ds_format->depth_size;
- }
+ copy_format(adapter, depth_view_format, ds_format);
+ depth_view_format->red_size = depth_view_format->depth_size;
+ depth_view_format->depth_size = 0;
+ depth_view_format->stencil_size = 0;
}
if ((format_id = typeless_depth_stencil_formats[i].stencil_view_id))
{
if (!(stencil_view_format = get_format_internal(adapter, format_id)))
return FALSE;
copy_format(adapter, stencil_view_format, ds_format);
- if (typeless_depth_stencil_formats[i].separate_depth_view_format)
- stencil_view_format->depth_size = 0;
+ stencil_view_format->green_size = stencil_view_format->stencil_size;
+ stencil_view_format->depth_size = 0;
+ stencil_view_format->stencil_size = 0;
}
}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 1ee22808c1d..67756a6bbfc 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -5236,8 +5236,8 @@ static inline void wined3d_context_copy_bo_address(struct wined3d_context *conte
static inline BOOL wined3d_dsv_srv_conflict(const struct wined3d_rendertarget_view *dsv,
const struct wined3d_format *srv_format)
{
- return !srv_format || (srv_format->depth_size && !(dsv->desc.flags & WINED3D_VIEW_READ_ONLY_DEPTH))
- || (srv_format->stencil_size && !(dsv->desc.flags & WINED3D_VIEW_READ_ONLY_STENCIL));
+ return !srv_format || (srv_format->red_size && !(dsv->desc.flags & WINED3D_VIEW_READ_ONLY_DEPTH))
+ || (srv_format->green_size && !(dsv->desc.flags & WINED3D_VIEW_READ_ONLY_STENCIL));
}
static inline BOOL wined3d_resource_check_fbo_attached(const struct wined3d_state *state,
--
2.11.0
Dec. 3, 2019