diff --git a/dlls/xmllite/reader.c b/dlls/xmllite/reader.c index 9193d2f5e29..ec2a071bb78 100644 --- a/dlls/xmllite/reader.c +++ b/dlls/xmllite/reader.c @@ -53,7 +53,8 @@ typedef enum XmlReadInState_DTD_Misc, XmlReadInState_Element, XmlReadInState_Content, - XmlReadInState_MiscEnd + XmlReadInState_MiscEnd, /* optional Misc at the end of a document */ + XmlReadInState_Eof } XmlReaderInternalState; /* This state denotes where parsing was interrupted by input problem. @@ -65,7 +66,8 @@ typedef enum XmlReadResumeState_PIBody, XmlReadResumeState_CDATA, XmlReadResumeState_Comment, - XmlReadResumeState_STag + XmlReadResumeState_STag, + XmlReadResumeState_CharData } XmlReaderResumeState; /* saved pointer index to resume from particular input position */ @@ -73,7 +75,7 @@ typedef enum { XmlReadResume_Name, /* PITarget, name for NCName, prefix for QName */ XmlReadResume_Local, /* local for QName */ - XmlReadResume_Body, /* PI body, comment text, CDATA text */ + XmlReadResume_Body, /* PI body, comment text, CDATA text, CharData text */ XmlReadResume_Last } XmlReaderResume; @@ -1788,6 +1790,10 @@ static HRESULT reader_parse_endtag(xmlreader *reader) reader_pop_element(reader); + /* It was a root element, the rest is expected as Misc */ + if (list_empty(&reader->elements)) + reader->instate = XmlReadInState_MiscEnd; + reader->nodetype = XmlNodeType_EndElement; reader_set_strvalue(reader, StringValue_LocalName, &local); reader_set_strvalue(reader, StringValue_QualifiedName, &qname); @@ -1867,8 +1873,48 @@ static HRESULT reader_parse_reference(xmlreader *reader) /* [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */ static HRESULT reader_parse_chardata(xmlreader *reader) { - FIXME("CharData not supported\n"); - return E_NOTIMPL; + WCHAR *start, *ptr; + + if (reader->resume[XmlReadResume_Body]) + { + start = reader->resume[XmlReadResume_Body]; + ptr = reader_get_cur(reader); + } + else + { + reader_shrink(reader); + ptr = start = reader_get_cur(reader); + /* There's no text */ + if (!*ptr || *ptr == '<') return S_OK; + reader->nodetype = XmlNodeType_Text; + reader->resume[XmlReadResume_Body] = start; + reader->resumestate = XmlReadResumeState_CharData; + reader_set_strvalue(reader, StringValue_LocalName, &strval_empty); + reader_set_strvalue(reader, StringValue_QualifiedName, &strval_empty); + reader_set_strvalue(reader, StringValue_Value, NULL); + } + + while (*ptr) + { + /* CDATA closing sequence ']]>' is not allowed */ + if (ptr[0] == ']' && ptr[1] == ']' && ptr[2] == '>') + return WC_E_CDSECTEND; + + /* Found next markup part */ + if (ptr[0] == '<') + { + strval value; + + reader_init_strvalue(start, ptr-start, &value); + reader_set_strvalue(reader, StringValue_Value, &value); + return S_OK; + } + + reader_skipn(reader, 1); + ptr++; + } + + return S_OK; } /* [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* */ @@ -1889,6 +1935,8 @@ static HRESULT reader_parse_content(xmlreader *reader) case XmlReadResumeState_PIBody: case XmlReadResumeState_PITarget: return reader_parse_pi(reader); + case XmlReadResumeState_CharData: + return reader_parse_chardata(reader); default: ERR("unknown resume state %d\n", reader->resumestate); } @@ -1986,6 +2034,15 @@ static HRESULT reader_parse_nextnode(xmlreader *reader) return reader_parse_element(reader); case XmlReadInState_Content: return reader_parse_content(reader); + case XmlReadInState_MiscEnd: + hr = reader_parse_misc(reader); + if (FAILED(hr)) return hr; + + if (hr == S_FALSE) + reader->instate = XmlReadInState_Eof; + return hr; + case XmlReadInState_Eof: + return S_FALSE; default: FIXME("internal state %d not handled\n", reader->instate); return E_NOTIMPL; diff --git a/dlls/xmllite/tests/reader.c b/dlls/xmllite/tests/reader.c index 46c6eddb396..c66671209c9 100644 --- a/dlls/xmllite/tests/reader.c +++ b/dlls/xmllite/tests/reader.c @@ -1418,6 +1418,106 @@ static void test_read_cdata(void) IXmlReader_Release(reader); } +static struct test_entry text_tests[] = { + { "simple text", "", "simple text", S_OK }, + { "text ]]> text", "", "", WC_E_CDSECTEND }, + { NULL } +}; + +static void test_read_text(void) +{ + struct test_entry *test = text_tests; + IXmlReader *reader; + HRESULT hr; + + hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL); + ok(hr == S_OK, "S_OK, got %08x\n", hr); + + while (test->xml) + { + XmlNodeType type; + IStream *stream; + + stream = create_stream_on_data(test->xml, strlen(test->xml)+1); + hr = IXmlReader_SetInput(reader, (IUnknown*)stream); + ok(hr == S_OK, "got %08x\n", hr); + + type = XmlNodeType_None; + hr = IXmlReader_Read(reader, &type); + + /* read one more to get to CDATA */ + if (type == XmlNodeType_Element) + { + type = XmlNodeType_None; + hr = IXmlReader_Read(reader, &type); + } + + if (test->hr_broken) + ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml); + else + ok(hr == test->hr, "got %08x for %s\n", hr, test->xml); + if (hr == S_OK) + { + const WCHAR *str; + WCHAR *str_exp; + UINT len; + + ok(type == XmlNodeType_Text, "got %d for %s\n", type, test->xml); + + str_exp = a2w(test->name); + + len = 1; + str = NULL; + hr = IXmlReader_GetLocalName(reader, &str, &len); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(len == strlen(test->name), "got %u\n", len); + ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str)); + + str = NULL; + hr = IXmlReader_GetLocalName(reader, &str, NULL); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str)); + + free_str(str_exp); + + len = 1; + str = NULL; + hr = IXmlReader_GetQualifiedName(reader, &str, &len); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(len == strlen(test->name), "got %u\n", len); + str_exp = a2w(test->name); + ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str)); + free_str(str_exp); + + /* value */ + len = 1; + str = NULL; + hr = IXmlReader_GetValue(reader, &str, &len); + ok(hr == S_OK, "got 0x%08x\n", hr); + + str_exp = a2w(test->value); + if (test->todo) + { + todo_wine { + ok(len == strlen(test->value), "got %u\n", len); + ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str)); + } + } + else + { + ok(len == strlen(test->value), "got %u\n", len); + ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str)); + } + free_str(str_exp); + } + + IStream_Release(stream); + test++; + } + + IXmlReader_Release(reader); +} + START_TEST(reader) { HRESULT r; @@ -1439,6 +1539,7 @@ START_TEST(reader) test_read_pi(); test_read_dtd(); test_read_element(); + test_read_text(); test_read_full(); test_read_pending(); test_readvaluechunk();