From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/tests/tts.c | 48 +++++++++++++++++++------------------------ dlls/sapi/xml.c | 44 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 30 deletions(-)
diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index f355ff7c98d..dbb8736f76e 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -958,42 +958,36 @@ static void test_spvoice_ssml(void) reset_engine_params(&test_engine);
hr = ISpVoice_Speak(voice, text1, SPF_IS_XML | SPF_PARSE_SSML, NULL); - todo_wine ok(hr == S_OK, "got %#lx.\n", hr); - todo_wine ok(test_engine.frag_count == 1, "got %Iu.\n", test_engine.frag_count); - - if (test_engine.frag_count == 1) { - check_frag_text(0, L"text1"); - - check_frag_state_field(0, eAction, SPVA_Speak, "%d"); - ok(test_engine.frags[0].State.LangID == 0x409 || broken(test_engine.frags[0].State.LangID == 0) /* win7 */, - "got %#hx.\n", test_engine.frags[0].State.LangID); - check_frag_state_field(0, EmphAdj, 0, "%ld"); - check_frag_state_field(0, RateAdj, 0, "%ld"); - check_frag_state_field(0, Volume, 100, "%lu"); - check_frag_state_field(0, PitchAdj.MiddleAdj, 0, "%ld"); - check_frag_state_field(0, PitchAdj.RangeAdj, 0, "%ld"); - check_frag_state_field(0, SilenceMSecs, 0, "%lu"); - check_frag_state_field(0, ePartOfSpeech, SPPS_Unknown, "%#x"); - } + ok(hr == S_OK, "got %#lx.\n", hr); + ok(test_engine.frag_count == 1, "got %Iu.\n", test_engine.frag_count); + check_frag_text(0, L"text1"); + + check_frag_state_field(0, eAction, SPVA_Speak, "%d"); + ok(test_engine.frags[0].State.LangID == 0x409 || broken(test_engine.frags[0].State.LangID == 0) /* win7 */, + "got %#hx.\n", test_engine.frags[0].State.LangID); + check_frag_state_field(0, EmphAdj, 0, "%ld"); + check_frag_state_field(0, RateAdj, 0, "%ld"); + check_frag_state_field(0, Volume, 100, "%lu"); + check_frag_state_field(0, PitchAdj.MiddleAdj, 0, "%ld"); + check_frag_state_field(0, PitchAdj.RangeAdj, 0, "%ld"); + check_frag_state_field(0, SilenceMSecs, 0, "%lu"); + check_frag_state_field(0, ePartOfSpeech, SPPS_Unknown, "%#x");
reset_engine_params(&test_engine);
/* SSML autodetection when SPF_PARSE_SSML is not specified. */ hr = ISpVoice_Speak(voice, text1, SPF_IS_XML, NULL); - todo_wine ok(hr == S_OK, "got %#lx.\n", hr); - todo_wine ok(test_engine.frag_count == 1, "got %Iu.\n", test_engine.frag_count); - - if (test_engine.frag_count == 1) - check_frag_text(0, L"text1"); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(test_engine.frag_count == 1, "got %Iu.\n", test_engine.frag_count); + check_frag_text(0, L"text1");
reset_engine_params(&test_engine);
/* XML and SSML autodetection when SPF_IS_XML is not specified. */ hr = ISpVoice_Speak(voice, text1, SPF_DEFAULT, NULL); - todo_wine ok(hr == S_OK, "got %#lx.\n", hr); - todo_wine ok(test_engine.frag_count == 1, "got %Iu.\n", test_engine.frag_count); - if (test_engine.frag_count == 1) - check_frag_text(0, L"text1"); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(test_engine.frag_count == 1, "got %Iu.\n", test_engine.frag_count); + check_frag_text(0, L"text1");
reset_engine_params(&test_engine);
@@ -1009,7 +1003,7 @@ static void test_spvoice_ssml(void) reset_engine_params(&test_engine);
hr = ISpVoice_Speak(voice, text2, SPF_IS_XML | SPF_PARSE_SSML, NULL); - todo_wine ok(hr == S_OK || broken(hr == SPERR_UNSUPPORTED_FORMAT) /* win7 */, "got %#lx.\n", hr); + ok(hr == S_OK || broken(hr == SPERR_UNSUPPORTED_FORMAT) /* win7 */, "got %#lx.\n", hr);
if (hr == S_OK) { ok(test_engine.frag_count == 1, "got %Iu.\n", test_engine.frag_count); diff --git a/dlls/sapi/xml.c b/dlls/sapi/xml.c index 7ed7505f355..518a687a5e8 100644 --- a/dlls/sapi/xml.c +++ b/dlls/sapi/xml.c @@ -64,11 +64,14 @@ struct xml_attr
struct xml_parser { + const WCHAR *base; const WCHAR *ptr; const WCHAR *end; struct xml_attr namespaces[MAX_NAMESPACES]; int ns_pos; BOOL error; + + SPVTEXTFRAG *tail_frag; };
static const xmlstr_t empty_xmlstr; @@ -418,8 +421,40 @@ static BOOL next_text_or_xml_elem(struct xml_parser *parser, BOOL *is_text, stru
static HRESULT add_sapi_text_fragment(struct xml_parser *parser, const SPVSTATE *state) { - FIXME("stub.\n"); - return E_NOTIMPL; + const WCHAR *text, *ptr; + SPVTEXTFRAG *frag; + size_t len; + WCHAR *buf; + + if (parser->error) + return SPERR_UNSUPPORTED_FORMAT; + + text = parser->ptr; + + for (ptr = parser->ptr; ptr < parser->end; ptr++) if (*ptr == '<') break; + len = ptr - parser->ptr; + parser->ptr = ptr; + + if (!len) + return S_OK; + + if (!(frag = malloc(sizeof(*frag) + (len + 1) * sizeof(WCHAR)))) + return E_OUTOFMEMORY; + + buf = (WCHAR *)(frag + 1); + memcpy(buf, text, len * sizeof(WCHAR)); + buf[len] = 0; + + frag->pNext = NULL; + frag->State = *state; + frag->pTextStart = buf; + frag->ulTextLen = len; + frag->ulTextSrcOffset = text - parser->base; + + parser->tail_frag->pNext = frag; + parser->tail_frag = frag; + + return S_OK; }
static HRESULT parse_ssml_elems(struct xml_parser *parser, const SPVSTATE *state, const struct xml_elem *parent) @@ -504,11 +539,13 @@ static HRESULT parse_ssml_contents(const WCHAR *contents, const WCHAR *end, SPVS { struct xml_parser parser = {0}; struct xml_elem parent = {0}; + SPVTEXTFRAG head_frag = {0}; struct xml_elem elem; HRESULT hr;
- parser.ptr = contents; + parser.base = parser.ptr = contents; parser.end = end; + parser.tail_frag = &head_frag;
/* Default SSML namespace. */ parser.namespaces[0].name = empty_xmlstr; @@ -541,6 +578,7 @@ static HRESULT parse_ssml_contents(const WCHAR *contents, const WCHAR *end, SPVS return SPERR_UNSUPPORTED_FORMAT; }
+ *frag_list = head_frag.pNext; return S_OK; }