diff --git a/dlls/xmllite/reader.c b/dlls/xmllite/reader.c
index 9216127b10c..6fd0f6917a7 100644
--- a/dlls/xmllite/reader.c
+++ b/dlls/xmllite/reader.c
@@ -63,6 +63,7 @@ typedef enum
XmlReadResumeState_Initial,
XmlReadResumeState_PITarget,
XmlReadResumeState_PIBody,
+ XmlReadResumeState_CDATA,
XmlReadResumeState_Comment,
XmlReadResumeState_STag
} XmlReaderResumeState;
@@ -72,7 +73,7 @@ typedef enum
{
XmlReadResume_Name, /* PITarget, name for NCName, prefix for QName */
XmlReadResume_Local, /* local for QName */
- XmlReadResume_Body, /* PI body, comment text */
+ XmlReadResume_Body, /* PI body, comment text, CDATA text */
XmlReadResume_Last
} XmlReaderResume;
@@ -1772,8 +1773,51 @@ static HRESULT reader_parse_endtag(xmlreader *reader)
[21] CDEnd ::= ']]>' */
static HRESULT reader_parse_cdata(xmlreader *reader)
{
- FIXME("CDATA sections are 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
+ {
+ /* skip markup 'nodetype = XmlNodeType_CDATA;
+ reader->resume[XmlReadResume_Body] = start;
+ reader->resumestate = XmlReadResumeState_CDATA;
+ reader_set_strvalue(reader, StringValue_LocalName, NULL);
+ reader_set_strvalue(reader, StringValue_QualifiedName, NULL);
+ reader_set_strvalue(reader, StringValue_Value, NULL);
+ }
+
+ while (*ptr)
+ {
+ if (*ptr == ']' && *(ptr+1) == ']' && *(ptr+2) == '>')
+ {
+ strval value = { start, ptr-start };
+
+ TRACE("%s\n", debugstr_wn(start, ptr-start));
+ /* skip ']]>' */
+ reader_skipn(reader, 3);
+ reader_set_strvalue(reader, StringValue_LocalName, &strval_empty);
+ reader_set_strvalue(reader, StringValue_QualifiedName, &strval_empty);
+ reader_set_strvalue(reader, StringValue_Value, &value);
+ reader->resume[XmlReadResume_Body] = NULL;
+ reader->resumestate = XmlReadResumeState_Initial;
+ return S_OK;
+ }
+ else
+ {
+ reader_skipn(reader, 1);
+ ptr++;
+ }
+ }
+
+ return S_OK;
}
/* [66] CharRef ::= '' [0-9]+ ';' | '' [0-9a-fA-F]+ ';'
@@ -1799,6 +1843,17 @@ static HRESULT reader_parse_content(xmlreader *reader)
static const WCHAR etagW[] = {'<','/',0};
static const WCHAR ampW[] = {'&',0};
+ if (reader->resumestate != XmlReadResumeState_Initial)
+ {
+ switch (reader->resumestate)
+ {
+ case XmlReadResumeState_CDATA:
+ return reader_parse_cdata(reader);
+ default:
+ ERR("unknown resume state %d\n", reader->resumestate);
+ }
+ }
+
reader_shrink(reader);
/* handle end tag here, it indicates end of content as well */
diff --git a/dlls/xmllite/tests/reader.c b/dlls/xmllite/tests/reader.c
index 9829452d079..7373a696c33 100644
--- a/dlls/xmllite/tests/reader.c
+++ b/dlls/xmllite/tests/reader.c
@@ -1318,6 +1318,88 @@ todo_wine
IXmlReader_Release(reader);
}
+static struct test_entry cdata_tests[] = {
+ { "", "", " ]]data ", S_OK },
+ { "", "", "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_CDATA, "got %d for %s\n", type, test->xml);
+
+ 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);
+ str_exp = a2w(test->name);
+ 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);
+ ok(len == strlen(test->value), "got %u\n", len);
+ str_exp = a2w(test->value);
+ 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;
@@ -1334,6 +1416,7 @@ START_TEST(reader)
test_reader_create();
test_readerinput();
test_reader_state();
+ test_read_cdata();
test_read_comment();
test_read_pi();
test_read_dtd();