summaryrefslogtreecommitdiffstats
path: root/sw/qa/extras/htmlexport
diff options
context:
space:
mode:
Diffstat (limited to 'sw/qa/extras/htmlexport')
-rw-r--r--sw/qa/extras/htmlexport/data/HTMLImage.odtbin0 -> 9721 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/NestingInA1.fodt47
-rw-r--r--sw/qa/extras/htmlexport/data/TableWithIndent.fodt22
-rw-r--r--sw/qa/extras/htmlexport/data/charborder.odtbin0 -> 7773 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/checkbox-radiobutton.docbin0 -> 35328 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/clearing-break.html8
-rw-r--r--sw/qa/extras/htmlexport/data/embedded_formula.fodt30
-rw-r--r--sw/qa/extras/htmlexport/data/extb.html10
-rw-r--r--sw/qa/extras/htmlexport/data/fdo62336.docxbin0 -> 21361 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/fdo81276.html21
-rw-r--r--sw/qa/extras/htmlexport/data/fdo86857.html29
-rw-r--r--sw/qa/extras/htmlexport/data/field-shade-reqif.odtbin0 -> 8903 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/field-shade.odtbin0 -> 8592 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/frameWithText.fodt25
-rw-r--r--sw/qa/extras/htmlexport/data/hello.html8
-rw-r--r--sw/qa/extras/htmlexport/data/image_anchored_to_paragraph_no_wrap.fodt20
-rw-r--r--sw/qa/extras/htmlexport/data/list.html4
-rw-r--r--sw/qa/extras/htmlexport/data/listItemSubheader.fodt31
-rw-r--r--sw/qa/extras/htmlexport/data/listsWithNumFormat.fodt74
-rw-r--r--sw/qa/extras/htmlexport/data/no-ole2-pres-data.odtbin0 -> 25483 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/ole1-pres-data-wmf.odtbin0 -> 41595 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/ole2.odtbin0 -> 19450 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/ole2.ole1014
-rw-r--r--sw/qa/extras/htmlexport/data/ole2.pngbin0 -> 766 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/paint-ole-bitmap-format.odtbin0 -> 21219 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/paint-ole.ole199
-rw-r--r--sw/qa/extras/htmlexport/data/paint-ole.pngbin0 -> 1505 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/paint-ole.xhtml9
-rw-r--r--sw/qa/extras/htmlexport/data/pdf-ole.odtbin0 -> 41839 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-aschar-objsize.odtbin0 -> 70411 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-chinese.odtbin0 -> 8350 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-jpg-img.xhtml4
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-list.xhtml11
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-no-lang.odtbin0 -> 8340 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-objdata-presentationdatasize.odtbin0 -> 95777 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-ole-data.ole1
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-ole-data.xhtml3
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-ole-img.jpgbin0 -> 696 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-ole-img.pngbin0 -> 766 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-ole-img.xhtml6
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-ole-nodata.odtbin0 -> 8178 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-ole-odg.ole146
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-ole-odg.pngbin0 -> 1486 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-ole-odg.xhtml9
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-ole2.xhtml5
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-p.xhtml8
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-png-img.xhtml4
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-table.xhtml9
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-table2.odtbin0 -> 8489 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/reqif-transparent-tif-img.odtbin0 -> 13339 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/skipimage-embedded-document.docxbin0 -> 21379 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/skipimage-embedded.docbin0 -> 35840 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/sub_li_and_ctd.fodt33
-rw-r--r--sw/qa/extras/htmlexport/data/tableRight.fodt22
-rw-r--r--sw/qa/extras/htmlexport/data/table_cell_padding.fodt34
-rw-r--r--sw/qa/extras/htmlexport/data/table_with_wide_horizontal_border.fodt27
-rw-r--r--sw/qa/extras/htmlexport/data/tdf126879.odtbin0 -> 8250 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/tdf132739.odtbin0 -> 8832 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/tdf155871.fodt21
-rw-r--r--sw/qa/extras/htmlexport/data/tdf66822.odtbin0 -> 10294 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/tdf76291.odtbin0 -> 10342 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/tdf83890.odtbin0 -> 9292 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/tdf90905.odtbin0 -> 12166 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/test_no_space_preserve.fodt25
-rw-r--r--sw/qa/extras/htmlexport/data/textAndImage.docxbin0 -> 6037 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/transparent-image.odtbin0 -> 12432 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/transparent.pngbin0 -> 2950 bytes
-rw-r--r--sw/qa/extras/htmlexport/data/twoListsWithSameStyle.fodt19
-rw-r--r--sw/qa/extras/htmlexport/data/xhtml-css.odtbin0 -> 8559 bytes
-rw-r--r--sw/qa/extras/htmlexport/htmlexport.cxx3037
-rw-r--r--sw/qa/extras/htmlexport/xhtmlexport.cxx187
71 files changed, 5162 insertions, 0 deletions
diff --git a/sw/qa/extras/htmlexport/data/HTMLImage.odt b/sw/qa/extras/htmlexport/data/HTMLImage.odt
new file mode 100644
index 0000000000..c938c3fd97
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/HTMLImage.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/NestingInA1.fodt b/sw/qa/extras/htmlexport/data/NestingInA1.fodt
new file mode 100644
index 0000000000..439ef0a57d
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/NestingInA1.fodt
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+ <office:text>
+ <table:table table:name="Outer">
+ <table:table-column table:number-columns-repeated="2"/>
+ <table:table-row>
+ <table:table-cell office:value-type="string">
+ <table:table table:name="Inner">
+ <table:table-column table:number-columns-repeated="2"/>
+ <table:table-row>
+ <table:table-cell office:value-type="string">
+ <text:p>Inner.A1</text:p>
+ </table:table-cell>
+ <table:table-cell office:value-type="string">
+ <text:p>Inner.B1</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell office:value-type="string">
+ <text:p>Inner.A2</text:p>
+ </table:table-cell>
+ <table:table-cell office:value-type="string">
+ <text:p>Inner.B2</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p>Outer.A1</text:p>
+ </table:table-cell>
+ <table:table-cell office:value-type="string">
+ <text:p>Outer.B1</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell office:value-type="string">
+ <text:p>Outer.A2</text:p>
+ </table:table-cell>
+ <table:table-cell office:value-type="string">
+ <text:p>Outer.B2</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p>Following text</text:p>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/TableWithIndent.fodt b/sw/qa/extras/htmlexport/data/TableWithIndent.fodt
new file mode 100644
index 0000000000..5daaa75e8e
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/TableWithIndent.fodt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:automatic-styles>
+ <style:style style:name="Table1" style:family="table">
+ <style:table-properties style:width="14cm" fo:margin-left="3cm" table:align="left"/>
+ </style:style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <table:table table:name="Table1" table:style-name="Table1">
+ <table:table-column/>
+ <table:table-row>
+ <table:table-cell office:value-type="string">
+ <text:p/>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p/>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/charborder.odt b/sw/qa/extras/htmlexport/data/charborder.odt
new file mode 100644
index 0000000000..e9667b2da4
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/charborder.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/checkbox-radiobutton.doc b/sw/qa/extras/htmlexport/data/checkbox-radiobutton.doc
new file mode 100644
index 0000000000..17162a4101
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/checkbox-radiobutton.doc
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/clearing-break.html b/sw/qa/extras/htmlexport/data/clearing-break.html
new file mode 100644
index 0000000000..9586cb3af8
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/clearing-break.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>
+<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABlElEQVR4nKWSQasBURiGX91zk5KykUKysPEjlFhIVqNmMSmjUfY2lC1FNrKj1C13pS4rFsL8BvMDpkRZWCnTRN3mOkej696x4a05PdM55/3ezvcRwzDwiggv2l5yIHQZfgyfusyL/NWAajR6gyzLSCQScLvdUFUVHo8HTqfTklMp7ZqAVm82VfT7fSyXS9jtdpzPZ0SjUWy3W2YqiuI/HgxklpzQypVKBdlsFn6/H61WC4fDAbVajf3HYjFMp9NLxZQFKyDdbpdFURQF+/0epVKJJTBFTebz+UMmi8XiZpDP51EulxEKhdgBU4FA4CHfHpFqMpmwz+v1QpIkVKtVOBwOtqfruiWTeDyO2Wx2M/H5fNA0DfV6HZFIBIIgYLPZYDweWzIpFot3Bp1OB8fjEblcDuv1GrvdjrVttVpZMuG4bzQaDdYJqna7DTreNKLL5WKtKxQKrDt/WRDe6SjzrJ/h8Bd6vR7boEomkwgGg8hkMpacTuv3k0iTcJx0IenXs+o4nT4t2RQxZ/pZXUbZsD19+6IfJMHZoeveMPgAAAAASUVORK5CYII=" name="Image1" align="left" width="68" height="68" border="0"/>
+foo<br clear="all"/>bar</p>
+</body>
+</html>
diff --git a/sw/qa/extras/htmlexport/data/embedded_formula.fodt b/sw/qa/extras/htmlexport/data/embedded_formula.fodt
new file mode 100644
index 0000000000..46e5391223
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/embedded_formula.fodt
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+ <office:text>
+ <text:p>Formula:</text:p>
+ <text:p><draw:frame draw:name="Formula1" text:anchor-type="as-char" svg:width="1.549cm" svg:height="0.531cm"><draw:object>
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+ <semantics>
+ <mrow>
+ <msup>
+ <mi mathvariant="normal">e</mi>
+ <mrow>
+ <mi>i</mi>
+ <mi>π</mi>
+ </mrow>
+ </msup>
+ <mo stretchy="false">+</mo>
+ <mn>1</mn>
+ <mo stretchy="false">=</mo>
+ <mn>0</mn>
+ </mrow>
+ <annotation encoding="StarMath 5.0">{ func e ^ { i %pi } + 1 } = 0</annotation>
+ </semantics>
+ </math>
+ </draw:object>
+ </draw:frame></text:p>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/extb.html b/sw/qa/extras/htmlexport/data/extb.html
new file mode 100644
index 0000000000..be73feadf8
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/extb.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8"/>
+</head>
+<body>
+<p>𤭢</p>
+<p>&#x24b62;</p>
+</body>
+</html>
diff --git a/sw/qa/extras/htmlexport/data/fdo62336.docx b/sw/qa/extras/htmlexport/data/fdo62336.docx
new file mode 100644
index 0000000000..f14a0e0019
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/fdo62336.docx
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/fdo81276.html b/sw/qa/extras/htmlexport/data/fdo81276.html
new file mode 100644
index 0000000000..653f6b1821
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/fdo81276.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html lang="ru-ru" >
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <meta charset="utf-8">
+ <style>
+
+ @page { size: 29.7cm 21cm;
+ margin-left: 0.5cm;
+ margin-right: 0.5cm;
+ margin-top: 2cm;
+ margin-bottom: 0.5cm
+ }
+
+ </style>
+</head>
+
+<body>
+
+</body>
+</html>
diff --git a/sw/qa/extras/htmlexport/data/fdo86857.html b/sw/qa/extras/htmlexport/data/fdo86857.html
new file mode 100644
index 0000000000..dc1fd88866
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/fdo86857.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
+ <title></title>
+ <meta name="generator" content="LibreOfficeDev 4.3.6.0.0 (Linux)"/>
+ <style type="text/css">
+ @page { margin: 2cm }
+ p { margin-bottom: 0.25cm; line-height: 120% }
+ td p { margin-bottom: 0cm }
+ a:link { so-language: zxx }
+ </style>
+</head>
+<body lang="de-DE" bgcolor="#ff0000" dir="ltr" style="background: #ff0000">
+<table width="100%" cellpadding="4" cellspacing="0">
+ <col width="256*">
+ <tr>
+ <td width="100%" valign="top" bgcolor="#66ffff" style="border: 1px solid #000000; padding: 0.1cm">
+ <p><br/>
+
+ </p>
+ </td>
+ </tr>
+</table>
+<p style="margin-bottom: 0cm; line-height: 100%"><br/>
+
+</p>
+</body>
+</html>
diff --git a/sw/qa/extras/htmlexport/data/field-shade-reqif.odt b/sw/qa/extras/htmlexport/data/field-shade-reqif.odt
new file mode 100644
index 0000000000..be7ec90f5a
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/field-shade-reqif.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/field-shade.odt b/sw/qa/extras/htmlexport/data/field-shade.odt
new file mode 100644
index 0000000000..2533be68c4
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/field-shade.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/frameWithText.fodt b/sw/qa/extras/htmlexport/data/frameWithText.fodt
new file mode 100644
index 0000000000..97ee5b1059
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/frameWithText.fodt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:styles>
+ <style:style style:name="Frame" style:family="graphic">
+ <style:graphic-properties text:anchor-type="paragraph" svg:x="0mm" svg:y="0mm" fo:margin-left="2mm" fo:margin-right="2mm" fo:margin-top="2mm" fo:margin-bottom="2mm" style:wrap="parallel" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" style:vertical-pos="top" style:vertical-rel="paragraph-content" style:horizontal-pos="center" style:horizontal-rel="paragraph-content" fo:padding="1.5mm" fo:border="0.06pt solid #000000"/>
+ </style:style>
+ </office:styles>
+ <office:automatic-styles>
+ <style:style style:name="fr1" style:family="graphic" style:parent-style-name="Frame">
+ <style:graphic-properties style:wrap="parallel" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="middle" style:vertical-rel="baseline" style:horizontal-pos="from-left" style:horizontal-rel="paragraph"/>
+ </style:style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <text:p>A frame with text below</text:p>
+ <text:p><draw:frame draw:style-name="fr1" draw:name="Frame1" text:anchor-type="as-char" svg:width="50mm" draw:z-index="0">
+ <draw:text-box fo:min-height="27mm">
+ <text:p text:style-name="P1">Some text in frame &amp; &lt;foo&gt;</text:p>
+ </draw:text-box>
+ </draw:frame></text:p>
+ <text:p>A text after the frame</text:p>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/hello.html b/sw/qa/extras/htmlexport/data/hello.html
new file mode 100644
index 0000000000..bc4180d17b
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/hello.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>Title of document</title>
+ </head>
+ <body>hello world</body>
+</html>
diff --git a/sw/qa/extras/htmlexport/data/image_anchored_to_paragraph_no_wrap.fodt b/sw/qa/extras/htmlexport/data/image_anchored_to_paragraph_no_wrap.fodt
new file mode 100644
index 0000000000..f108072430
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/image_anchored_to_paragraph_no_wrap.fodt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:automatic-styles>
+ <style:style style:name="fr1" style:family="graphic" style:parent-style-name="OLE">
+ <style:graphic-properties style:wrap="none"/>
+ </style:style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <text:p><draw:frame draw:style-name="fr1" draw:name="Image1" text:anchor-type="paragraph" svg:width="17cm" svg:height="13cm"><draw:image draw:mime-type="image/svg+xml">
+ <office:binary-data>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB4bWxucz0iaHR0
+ cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDIw
+ IDIwIiBzdHJva2U9ImJsYWNrIj4KPHBhdGggZD0iTTEsMUwxOSwxOSIvPgo8L3N2Zz4=
+ </office:binary-data>
+ </draw:image>
+ </draw:frame></text:p>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/list.html b/sw/qa/extras/htmlexport/data/list.html
new file mode 100644
index 0000000000..867521155a
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/list.html
@@ -0,0 +1,4 @@
+<ul>
+ <li>foo</li>
+ <li>bar</li>
+</ul>
diff --git a/sw/qa/extras/htmlexport/data/listItemSubheader.fodt b/sw/qa/extras/htmlexport/data/listItemSubheader.fodt
new file mode 100644
index 0000000000..4c68ce8876
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/listItemSubheader.fodt
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+ <office:text>
+ <text:p/>
+ <text:list>
+ <text:list-item>
+ <text:p>list 1 item 1</text:p>
+ <text:list>
+ <text:list-header>
+ <text:p>list 1 item 1 sub-header</text:p>
+ </text:list-header>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ <text:p/>
+ <text:p>text</text:p>
+ <text:list text:continue-numbering="true">
+ <text:list-item>
+ <text:list>
+ <text:list-header>
+ <text:p>list 2 sub-header</text:p>
+ </text:list-header>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ <text:p/>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/listsWithNumFormat.fodt b/sw/qa/extras/htmlexport/data/listsWithNumFormat.fodt
new file mode 100644
index 0000000000..c9a8225662
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/listsWithNumFormat.fodt
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:automatic-styles>
+ <text:list-style style:name="A_upper">
+ <text:list-level-style-number text:level="1" style:num-suffix="." style:num-format="A"/>
+ </text:list-style>
+ <text:list-style style:name="a_lower">
+ <text:list-level-style-number text:level="1" style:num-suffix="." style:num-format="a"/>
+ </text:list-style>
+ <text:list-style style:name="I_upper">
+ <text:list-level-style-number text:level="1" style:num-suffix="." style:num-format="I"/>
+ </text:list-style>
+ <text:list-style style:name="i_lower">
+ <text:list-level-style-number text:level="1" style:num-suffix="." style:num-format="i"/>
+ </text:list-style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <text:p>List A</text:p>
+ <text:list text:style-name="A_upper">
+ <text:list-item>
+ <text:p>First</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p>Second</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p>Third</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p/>
+ <text:p>List a</text:p>
+ <text:list text:style-name="a_lower">
+ <text:list-item>
+ <text:p>First</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p>Second</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p>Third</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p/>
+ <text:p>List I</text:p>
+ <text:list text:style-name="I_upper">
+ <text:list-item>
+ <text:p>First</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p>Second</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p>Third</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p/>
+ <text:p>List i</text:p>
+ <text:list text:style-name="i_lower">
+ <text:list-item>
+ <text:p>First</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p>Second</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p>Third</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p/>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/no-ole2-pres-data.odt b/sw/qa/extras/htmlexport/data/no-ole2-pres-data.odt
new file mode 100644
index 0000000000..cd65a17557
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/no-ole2-pres-data.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/ole1-pres-data-wmf.odt b/sw/qa/extras/htmlexport/data/ole1-pres-data-wmf.odt
new file mode 100644
index 0000000000..9bcca729bc
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/ole1-pres-data-wmf.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/ole2.odt b/sw/qa/extras/htmlexport/data/ole2.odt
new file mode 100644
index 0000000000..a10cfbb5b5
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/ole2.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/ole2.ole b/sw/qa/extras/htmlexport/data/ole2.ole
new file mode 100644
index 0000000000..96407e88fa
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/ole2.ole
@@ -0,0 +1,1014 @@
+{\object\objemb{\*\objclass PowerPoint.Show.12}\objw10020\objh5638{\*\objdata
+01050000
+02000000
+13000000
+506f776572506f696e742e53686f772e313200
+00000000
+00000000
+00940000
+d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000
+0000000000010000000100000000000000001000000200000001000000feffffff000000000000
+0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffdffffff47000000feffffff48000000050000000600000007000000080000000900
+00000a0000000b0000000c0000000d0000000e0000000f00000010000000110000001200000013
+0000001400000015000000160000001700000018000000190000001a0000001b0000001c000000
+1d0000001e0000001f000000200000002100000022000000230000002400000025000000260000
+002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f0000003000
+00003100000032000000330000003400000035000000360000003700000038000000390000003a
+0000003b0000003c0000003d0000003e0000003f00000040000000410000004200000043000000
+440000004500000046000000fefffffffefffffffeffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000016000500
+ffffffffffffffff02000000f4554fcf878f474d80bb5808164bb3f80000000000000000000000
+0080609bf8f8bcd30103000000000300000000000001004f006c00650000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000a000201ffffffffffffffffffffffff00000000000000000000000000000000
+00000000000000000000000000000000000000000000000014000000000000005000610063006b
+006100670065000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000100002010100000004000000ffffffff0000000000
+000000000000000000000000000000000000000000000000000000000000000400000056840000
+00000000010043006f006d0070004f0062006a0000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000012000200ffffffffffff
+ffffffffffff000000000000000000000000000000000000000000000000000000000000000000
+000000010000007c00000000000000feffffff02000000feffffff040000000500000006000000
+0700000008000000090000000a000000fefffffffeffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffff01000002000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+0000000000000100feff030a0000fffffffff4554fcf878f474d80bb5808164bb3f8220000004d
+6963726f736f667420506f776572506f696e742d5072e473656e746174696f6e000f0000004d53
+50726573656e746174696f6e0013000000506f776572506f696e742e53686f772e313200f439b2
+7100000000000000000000000000000000ffffffff030000000400000001000000ffffffff0200
+0000000000000a450000d8260000ba010000010009000003dd0000000600120000000000040000
+0003010800050000000b0200000000050000000c02cf08a80f030000001e0007000000fc020000
+ffffff000000040000002d01000008000000fa02050000000000ffffff00040000002d0101000e
+00000024030500ffffffffffffcf08a80fcf08a80fffffffffffff08000000fa02000000000000
+00000000040000002d01020007000000fc020000ffffff000000040000002d01030004000000f0
+01000007000000fc0200004472c4000000040000002d0100000400000006010100040000002d01
+0100120000002403070065026a03e4086a03e408af025a0a2504e4089b05e408e0046502e00404
+0000002d0102000400000006010100040000002d0103000800504b030414000600080000002100
+dfcc18f5ad010000460c0000130008025b436f6e74656e745f54797065735d2e786d6c20a20402
+28a000020000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000cc975b4fc23014c7df4dfc0e4b5f0d2ba0221a060f5e9ebc90881fa06e07
+a8766dd316846fefd90582849b02b12f4bcecef9ffcfaf6bb776adce2415c1188ce54a46a41656
+4900325609978388bcf51e2a4d1258c764c2849210912958d2699f9eb47a530d3640b5b411193a
+a76f28b5f110526643a54162a6af4cca1c866640358b3fd90068bd5a6dd0584907d2555ce641da
+ad3be8b39170c1fd046f17241f1a0624b82d0ab35e11e169669027e84a8d016197344c6bc163e6
+304fc7325922ab9454212af31a3be4da9e61c19a0e59667d8352f7828fd3f004822e33ee99a558
+45b576541bb0a8cb6bc3cd4e2b5055bfcf6348543c4a51122e9aa5e24718a68ccbd920d6c15881
+379f987538f58b41edd0640bde3b319534c7e1d8469069ba46697b8cf9c98db7118c397c1d8560
+6ebc8dc0e13b0cc575ff49c86db67664ef025edd54c0c147bd60bdd3ea7b64533572e51a2c82e3
+acc4c2fbaf4c750f99ce3d64baf090e9d243a686874c571e32353d64baf690a956f511eabfbee4
+28cf775e3cf71af83dc3ec909aa92b1a8dc038be793f9b7744ebbd070dd9f9378164456f9aff05
+b4bf010000ffff0300504b03041400060008000000210068f874a103010000e20200000b000802
+5f72656c732f2e72656c7320a2040228a000020000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000ac92db4a03311086ef05df21cc7d37
+db2a22d26c6f44e89dc8fa006332bb1bdd1c48a6d2bebda1e061612d82bdcccc3f1fdf24596ff6
+6e14ef94b20d5ec1b2aa4190d7c158df2b786e1f16b72032a33738064f0a0e9461d35c5eac9f68
+442e4379b0318b42f159c1c01cefa4cc7a2087b90a917ce9742139e4724cbd8ca8dfb027b9aaeb
+1b997e32a09930c5d628485b7305a23d44fa1f5b3a6234c8287548b488a94c27b66517d162ea89
+1598a01f4b391f135521839c175a9d5788879d7bf168c71995af5ef51aa9ff4d68f977a1d07556
+d37dd03b479ee7bca6896fa71859c644b9148fe95337747d4e21da337943e6f4a3618c9f4672f2
+339b0f000000ffff0300504b030414000600080000002100635c23b4c000000037010000200000
+007070742f736c696465732f5f72656c732f736c696465312e786d6c2e72656c738ccfbd6ac330
+1007f03dd07710b757b23b84102c65290543a7903ec0219d6d515b123ab9c46f1f8d3174c8785f
+bf3fd75deecb2cfe28b38f41432b1b10146c743e8c1a7e6e5fef27105c30389c63200d1b315ccc
+dba1bbd28ca51ef1e4138baa04d6309592ce4ab19d6841963151a89321e6054b2df3a812da5f1c
+497d34cd51e56703ccce14bdd3907bd782b86d895eb1e330784b9fd1ae0b85f24f84e2d93bfac6
+2daea5b298472a1aa47ceeef965a592340994eedde350f000000ffff0300504b03041400060008
+00000021001b2e35070c010000d00300001f0008017070742f5f72656c732f70726573656e7461
+74696f6e2e786d6c2e72656c7320a2040128a00001000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000ac93414ec3301045f748dcc19a3d7152a042a84e3708a90b2404e100269924168e6d79
+4c21b7c76aa12455157591e5fff6fc799ab157ebef4eb32d7a52d608c89214189ad256ca3402de
+8ac7ab3b6014a4a9a4b60605f448b0ce2f2f562fa8658845d42a472ca61812d086e0ee39a7b2c5
+4e52621d9a78525bdfc910a56fb893e5876c902fd274c9fd3003f25126db5402fca6ba0656f40e
+cfc9b675ad4a7cb0e56787269c68c19d477af636366385f40d0601072b8969c04f432ce68420ad
+2afc07d8c95f379b82c86687789214d01fa1eccdd18d49ace59c5841be6b7c0dbdc6c18a06e614
+c8edac20b176b0a49ddc9b93c3b8999361abf0ebe8b51eac3f083efa87f90f000000ffff030050
+4b030414000600080000002100bcd1a735de0200002c0e0000140000007070742f70726573656e
+746174696f6e2e786d6cec97cd6fda3014c0ef93f63f44be4e34385f0444a86034d3a44e42a5bb
+ece62606a23a71641b0a9df6bfefd97120a59ad4c38e3961fb7dfae7a7f0def4f65832e740852c
+7895207c33440ead329e17d536413f1fd3418c1ca9489513c62b9aa01395e876f6f9d3b49ed482
+4a5a29a2c0d40137959c9004ed94aa27ae2bb31d2d89bce135ad40b6e1a2240ab662ebe682bc80
+fb92b9de7018b925292a64edc547ecf966536474c9b37d09e11b2782329387dc15b56cbdd51ff1
+d6bdc5db94241500e617e76582c2211e8670440e74bd7f9254a5bc521280a11990902cff41a4a2
+e27b7e2fd5d58953e409f270300a623f0a00a798e8139060e4cea6ee3fccdfae1b2761d4b1f62e
+d65dddf5ab931d21310f8fe12ef09cd92941511cc67ae36aa58a2b2aad5a2b305a631c0467ad9c
+6ec89ea9477a546b7562743625fa6cb51276f5b0120e23ba4c723a58de996cba2aecc0700d3a25
+11f7098210846da1c4187240e7913cad5fdb887029c58c0a25f7d5423c6bae8e7ed0ca6e41b483
+505035ab7d95a986fb390b099e70acfd3c53a1ab182e6ee492b3224f0bc6cc46d700fdca847320
+104d1d1bfc575a26aaa34e355c3f837aff525603a6b42699507225a0a41164f24a90c90b8e078d
+c33df3b068bc0b9a201ce9847b3e068ae5e35ff8b4107a3e1a8ae5135cf8607f84a31e504bc502
+0a3b80622f36d9f78034150b28ba00f2bc3832ff023d204dc5021a75008d02bfff469fa95840f1
+0590a6d37fa4cf542ca0710750148efa8ff4998ae95cdfb798f504d6b6978595b31745827edfa5
+f374e1f9fe6018f9e920f016e120863fbdc17899fa698817733c9cffd18d380e7507fc6d5fe414
+9cb453000edfcd016591092ef946dd64bcb403855bf3172a6a5e9899027bcd14d078dd6a97a607
+8727e1a28081017c72f18a9c9a4bddde47c07d0f13c312861b0ddf1a66ccd48214dba733f37930
+f7e741d3bdb72a6665a25c07f46c083f0efe5f08b3eea032cf01c0dbdff6a83b1ccdfe020000ff
+ff0300504b030414000600080000002100303a84e5ea0200006c060000150000007070742f736c
+696465732f736c696465312e786d6c8c545b6f9b30147e9fb4ff8078a75c020450691548a8266d
+6bd4763fc033262019dbb2dd3451b5ff3edb98a45d23ad3c707c39dfb97ce71c5fdf1e46ecec11
+170325a51b5e05ae8308a4ed4076a5fbeba9f132d711129016604a50e91e91706f6fbe7eb96685
+c0ada3d04414a0747b2959e1fb02f66804e28a3244d45d47f908a4daf29ddf72f0a2ac8ed88f82
+20f5473010d7e2f967f0b4eb0688d6143e8f88c8c90847184815b9e80726666bec33d618474299
+31e87721dda8cce0236eb514ec8923a457647fc7d923db7273fd73bfe5ced02abe5c878051d1e2
+faf6c2aa992dd99b85ff0f7c372f4171e8f8a8a5cacd3994ae22ffa8ffbe3e4307e9c0e9109e4f
+617f7f4117f69b0bdafeecc07fe354673505f7319d784e67dba101176a037b8723d84be12c5c1b
+d47721e7f09ef950baaf4d1355c9a689bd46adbc38a862afdac4b9d7448b6c132d9b3a5aa47f34
+3a4c0bc891a1fcdba975c2f443b9c601722a6827af201d6ddde7f651950a63db3c3ae4d764d934
+6114575e1ed7991757e9dacb56abdc5b6749be08f3661584eb3f960d15f32c4d16be4ddeb270b1
+7067d62e962cccd2348c22538c28c8832059be2f5f1ae649122da7b244d1324d97ef8b030ac685
+bc437474f4a274f9b0ebe58a73fa6228077b15eb0498154d6853404aca23465a119307d4295294
+d3c8200d9fa8c6dcd9035cba0042d5f1e174d583164dc749a03e1bd1096176c6a0d6ee068c4fb6
+ad81cbb6273356dfd0d07508ca1338f83ff884309e293983c781507ec9003e7b9ef42782266258
+210f156d8f1af75b49d5eb5ce29a62332c80c09eaaf7074a3ed50d0bf9a88166c3cc4f2100de91
+374a88b45bc0c183bac140bf942df2d61b1b0333de67a7a65256ccafc9dc7f6665a7a8aaf234aa
+b3caabc2b8f1e275bef4564d9a784db288e3baca56f562a3a78885f1c72952879f9b22465f1067
+74300f6818d841322486e922cbb3659447260f13db2c4fd3621f4688f90fc0eef7662294338978
+6d8e981ed149f5aca27357b8bf000000ffff0300504b030414000600080000002100d5d192f1bc
+000000370100002c0000007070742f736c6964654c61796f7574732f5f72656c732f736c696465
+4c61796f7574362e786d6c2e72656c738ccfbd0ac2301007f05df01dc2ed26ad8388347511c1c1
+45f4018ee4da06db24e4a2e8db9bd18283e37dfdfe5cb37f4da378526217bc865a5620c89b609d
+ef35dcaec7d5160467f416c7e049c39b18f6ed72d15c68c45c8e78709145513c6b18728e3ba5d8
+0c3421cb10c9974917d284b994a95711cd1d7b52ebaadaa8f46d403b33c5c96a48275b83b8be23
+fd6387ae73860ec13c26f2f94784e2d1593a23674a85c5d453d620e5777fb654cb1201aa6dd4ec
+ddf6030000ffff0300504b030414000600080000002100d5d192f1bc000000370100002c000000
+7070742f736c6964654c61796f7574732f5f72656c732f736c6964654c61796f7574372e786d6c
+2e72656c738ccfbd0ac2301007f05df01dc2ed26ad8388347511c1c145f4018ee4da06db24e4a2
+e8db9bd18283e37dfdfe5cb37f4da378526217bc865a5620c89b609def35dcaec7d5160467f416
+c7e049c39b18f6ed72d15c68c45c8e78709145513c6b18728e3ba5d80c3421cb10c9974917d284
+b994a95711cd1d7b52ebaadaa8f46d403b33c5c96a48275b83b8be23fd6387ae73860ec13c26f2
+f94784e2d1593a23674a85c5d453d620e5777fb654cb1201aa6dd4ecddf6030000ffff0300504b
+030414000600080000002100d5d192f1bc000000370100002c0000007070742f736c6964654c61
+796f7574732f5f72656c732f736c6964654c61796f7574392e786d6c2e72656c738ccfbd0ac230
+1007f05df01dc2ed26ad8388347511c1c145f4018ee4da06db24e4a2e8db9bd18283e37dfdfe5c
+b37f4da378526217bc865a5620c89b609def35dcaec7d5160467f416c7e049c39b18f6ed72d15c
+68c45c8e78709145513c6b18728e3ba5d80c3421cb10c9974917d284b994a95711cd1d7b52ebaa
+daa8f46d403b33c5c96a48275b83b8be23fd6387ae73860ec13c26f2f94784e2d1593a23674a85
+c5d453d620e5777fb654cb1201aa6dd4ecddf6030000ffff0300504b0304140006000800000021
+00d5d192f1bc000000370100002d0000007070742f736c6964654c61796f7574732f5f72656c73
+2f736c6964654c61796f757431302e786d6c2e72656c738ccfbd0ac2301007f05df01dc2ed26ad
+8388347511c1c145f4018ee4da06db24e4a2e8db9bd18283e37dfdfe5cb37f4da378526217bc86
+5a5620c89b609def35dcaec7d5160467f416c7e049c39b18f6ed72d15c68c45c8e78709145513c
+6b18728e3ba5d80c3421cb10c9974917d284b994a95711cd1d7b52ebaadaa8f46d403b33c5c96a
+48275b83b8be23fd6387ae73860ec13c26f2f94784e2d1593a23674a85c5d453d620e5777fb654
+cb1201aa6dd4ecddf6030000ffff0300504b030414000600080000002100d5d192f1bc00000037
+0100002c0000007070742f736c6964654c61796f7574732f5f72656c732f736c6964654c61796f
+7574382e786d6c2e72656c738ccfbd0ac2301007f05df01dc2ed26ad8388347511c1c145f4018e
+e4da06db24e4a2e8db9bd18283e37dfdfe5cb37f4da378526217bc865a5620c89b609def35dcae
+c7d5160467f416c7e049c39b18f6ed72d15c68c45c8e78709145513c6b18728e3ba5d80c3421cb
+10c9974917d284b994a95711cd1d7b52ebaadaa8f46d403b33c5c96a48275b83b8be23fd6387ae
+73860ec13c26f2f94784e2d1593a23674a85c5d453d620e5777fb654cb1201aa6dd4ecddf60300
+00ffff0300504b030414000600080000002100d5d192f1bc000000370100002d0000007070742f
+736c6964654c61796f7574732f5f72656c732f736c6964654c61796f757431312e786d6c2e7265
+6c738ccfbd0ac2301007f05df01dc2ed26ad8388347511c1c145f4018ee4da06db24e4a2e8db9b
+d18283e37dfdfe5cb37f4da378526217bc865a5620c89b609def35dcaec7d5160467f416c7e049
+c39b18f6ed72d15c68c45c8e78709145513c6b18728e3ba5d80c3421cb10c9974917d284b994a9
+5711cd1d7b52ebaadaa8f46d403b33c5c96a48275b83b8be23fd6387ae73860ec13c26f2f94784
+e2d1593a23674a85c5d453d620e5777fb654cb1201aa6dd4ecddf6030000ffff0300504b030414
+000600080000002100d5d192f1bc000000370100002c0000007070742f736c6964654c61796f75
+74732f5f72656c732f736c6964654c61796f7574312e786d6c2e72656c738ccfbd0ac2301007f0
+5df01dc2ed26ad8388347511c1c145f4018ee4da06db24e4a2e8db9bd18283e37dfdfe5cb37f4d
+a378526217bc865a5620c89b609def35dcaec7d5160467f416c7e049c39b18f6ed72d15c68c45c
+8e78709145513c6b18728e3ba5d80c3421cb10c9974917d284b994a95711cd1d7b52ebaadaa8f4
+6d403b33c5c96a48275b83b8be23fd6387ae73860ec13c26f2f94784e2d1593a23674a85c5d453
+d620e5777fb654cb1201aa6dd4ecddf6030000ffff0300504b030414000600080000002100d5d1
+92f1bc000000370100002c0000007070742f736c6964654c61796f7574732f5f72656c732f736c
+6964654c61796f7574322e786d6c2e72656c738ccfbd0ac2301007f05df01dc2ed26ad83883475
+11c1c145f4018ee4da06db24e4a2e8db9bd18283e37dfdfe5cb37f4da378526217bc865a5620c8
+9b609def35dcaec7d5160467f416c7e049c39b18f6ed72d15c68c45c8e78709145513c6b18728e
+3ba5d80c3421cb10c9974917d284b994a95711cd1d7b52ebaadaa8f46d403b33c5c96a48275b83
+b8be23fd6387ae73860ec13c26f2f94784e2d1593a23674a85c5d453d620e5777fb654cb1201aa
+6dd4ecddf6030000ffff0300504b030414000600080000002100d5d192f1bc000000370100002c
+0000007070742f736c6964654c61796f7574732f5f72656c732f736c6964654c61796f7574332e
+786d6c2e72656c738ccfbd0ac2301007f05df01dc2ed26ad8388347511c1c145f4018ee4da06db
+24e4a2e8db9bd18283e37dfdfe5cb37f4da378526217bc865a5620c89b609def35dcaec7d51604
+67f416c7e049c39b18f6ed72d15c68c45c8e78709145513c6b18728e3ba5d80c3421cb10c99749
+17d284b994a95711cd1d7b52ebaadaa8f46d403b33c5c96a48275b83b8be23fd6387ae73860ec1
+3c26f2f94784e2d1593a23674a85c5d453d620e5777fb654cb1201aa6dd4ecddf6030000ffff03
+00504b030414000600080000002100d5d192f1bc000000370100002c0000007070742f736c6964
+654c61796f7574732f5f72656c732f736c6964654c61796f7574342e786d6c2e72656c738ccfbd
+0ac2301007f05df01dc2ed26ad8388347511c1c145f4018ee4da06db24e4a2e8db9bd18283e37d
+fdfe5cb37f4da378526217bc865a5620c89b609def35dcaec7d5160467f416c7e049c39b18f6ed
+72d15c68c45c8e78709145513c6b18728e3ba5d80c3421cb10c9974917d284b994a95711cd1d7b
+52ebaadaa8f46d403b33c5c96a48275b83b8be23fd6387ae73860ec13c26f2f94784e2d1593a23
+674a85c5d453d620e5777fb654cb1201aa6dd4ecddf6030000ffff0300504b0304140006000800
+0000210069a25f2115010000c70700002c0000007070742f736c6964654d6173746572732f5f72
+656c732f736c6964654d6173746572312e786d6c2e72656c73c4d54d6ac3301005e07da17730b3
+8f253b899394c8d98442a0ab921e4058e31f6a4b46524a7dfb8a96420c616821a08dc092f5e6e3
+6db43f7c0e7df281d675460bc8520e09eacaa84e3702dececf8b2d24ce4bad646f340a98d0c1a1
+7c7cd8bf622f7db8e4da6e744948d14e40ebfdf8c498ab5a1ca44bcd883a9cd4c60ed2874fdbb0
+5156efb24196735e307b9d01e52c33392901f6a4c2fcf334e25fb24d5d77151e4d751950fb1b23
+98eb3b852f7232171f62a56dd00b48d3ebfdd94fdb348c00765bb68c295b52b24d4cd9869265f9
+3d693edcc519ea7be767cd28c75d19ff6d28271b8a29233b2b62ca0ab2b3b8a591adad63d2d664
+6b3c6a6b9cb2ad62d256946c1753b6fb95b1d9f35b7e010000ffff0300504b0304140006000800
+00002100e40b4c2ac604000089100000220000007070742f736c6964654c61796f7574732f736c
+6964654c61796f757431312e786d6ccc58cd6edc3610be17e83b08bad32b891425195907fa6351
+347fa8dd1c7aa325ae5788fe4a71d7eb0401f2267d8e16bde54df2241d52929dd88eb32ee2c297
+2545cd0c67e6fb6648ed93a7bba6b6b6420e55d72e6df7c0b12dd1165d59b5674bfbb7138642db
+1a146f4b5e77ad58da1762b09f1efdf8c393fe70a8cb67fca2db280b6cb4c3215fda6ba5fac3c5
+6228d6a2e1c341d78b16dead3ad970058ff26c514a7e0eb69b7ae1390e5d34bc6aed495feea3df
+ad565521b2aed834a255a311296aaec0ff615df5c36caddfc75a2fc500668cf6972ea98b1ea285
+c4a8934ad5226ecb939d6d1979b98537ae7d0429288eebd26a79030baf41b47ac36b212dd010b5
+b5694beb44ec94111cfa1329849eb5db9f647fdcbf9246ffc5f695b4aa52db9becd88be9c52466
+1edbad992caea99fcd537eb85bc9468f901f6bb7b401c60bfdbbd06be084558c8bc5d56ab17e79
+8b6cb1ce6f915ecc1b2c3edb5447353a77331c6f0ee7465a74e28c4bcf06353bb791d5d27ec798
+97f8392388c10c11272128c949849887c3dc0b58ea61fa5e6bbbf4b090c280f6733993cfa53700
+6faa427643b7520745d74ccc99090858bb64c25a3bfc2e49a893e718a3d48942447c3f80dd4307
+2549c26246589e90e8fd940bf0791e4d148b29f42907332643ffac2bde0c56db01661ae211c24b
+8911573df6eb89704a93cdb63a59012d47fe4d5aa3a8995ca5ff56ecc3c0239133a28aa9ef7afe
+9734f0a8179af71a5e3f74dd1087d7411e4df7876a9774e585d63e8511c0d51e2d6dc135aea3d9
+7a50c7eaa216e6a1d73fc62909c235d75da41428cb475975644800e02821c742b4ca8d2cd6d62f
+7555bc11ad752ab83c1520d46a7fc634ebb88de9c59543c6c7bb39886fe32024a1876ef176cd6b
+70c1f21e291be38826cc0b33045b1244282528a629450e8bfc284fc23cc0dec3b351637e8d8ce0
+deee4af91ea4c4a1770727830013fc909cec351db7f5659fbb8ba3cc1073dbc99a9f01254b3118
+de8cac1deea6e8f5ed4ca6eedeeef7736dccca4f452bf6b0e87ddb62262b750f8bf8db165f5790
+dbfd2d923d92fcf19f767587c9fbd53a996b3de36ad30c9f97387ea4259e666114504c118b0894
+789445fac04911893d97b931ce823c7cf8122fa1a487b71009af5773718f47fe57abdbdc48ae17
+e157ca6e05f723136d84532fa5094638600c8e5716a128f04284d32866414cf28092f7f3b5abe4
+4aa8aa11ac3adb48f172a3ef503789640d8d4a6bc1dbcba256472e3d70f001a43abca214f86070
+6fcb575cf25f6fd2f1bf10ce9f09c7361fff7c2baa5ab49f938e3c52d279d4f1fc380a80740945
+2488139464b18fa2344e1d9f26b193e38727dd4ac991757f6c38b4153913ef1bc7ca7d88f77dd1
+a6976877351c86eda66984fc0270ff91021ea42427d4c5507211f4962c0851eca439f29d308949
+18f971fc3f7419f8547cb1696ec5dc1c67dfb9d9647916d09cf928a53882d6ca729478598a9893
+7b21a3ccf7dde8b2d90c75550a4074ef1ef3e9c35f2fe4c1a70f7f7f87166386f9d370cebb994d
+ec4992887a690865ea12e89b19946ecca88f988f094993304e71aed9d3bbe4267b60713ff6f4dd
+b9907d57992f6ad79908b4e5fa02e37b0e76b0e79a337d617c9bc74b961cebf861ace573debfdc
+1a9a8cd7a5d42cf59a9aa3e895888e7dfe0be1e85f000000ffff0300504b030414000600080000
+002100ee0bf3bf90040000a70f0000220000007070742f736c6964654c61796f7574732f736c69
+64654c61796f757431302e786d6ccc57db6edc36107d2fd07f10f44eeb46dd8cac03dd5814756c
+a376f3d0375ae27a85e8568abbde7560207fd2ef68d1b7fc49bea4434af2dab1e3ac031bf08b78
+d1703833e7cc907cf3765d57da8af1be6c9b996eed99bac69abc2dcae662a6ff714650a06bbda0
+4d41abb661337dc37afdedc1cf3fbde9f6fbaa38a49b762934d0d1f4fb74a62f84e8f60da3cf17
+aca6fd5edbb106fecd5b5e5301437e61149c5e82eeba326cd3f48c9a968d3eaee7bbac6fe7f332
+67699b2f6bd6884109671515607fbf28bb7ed2d6eda2ade3ac07356af55d93c4a6036f2130e26c
+ad6b4a8eaf60c6d20fc0f5fcb42ab486d63071560a5669cba6905114e5075a31ae9db1b550827d
+77c61993bd66f50bef4ebb13aed61fad4eb8561652dfa84737c61fa3981a362bd531be5a7e3175
+e9fe7ace6bd9425cb4f54c07f836f26bc8393042cb87c97c3b9b2f8e1f90cd17d903d2c6b48171
+6b53e9d560dc7d77ecc99d212c325aca8ec35e4c162d7939d33f1262c76e463022d043d88c318a
+331c22623b4166fb24b11def5aaeb6bcfd9c3385d0afc5c434cbbb876e5de6bceddbb9d8cbdb7a
+a4c9c43600d6c223b0d2ca8fb66f054eeac7c8719308e130b550ec3a094adcccc38e935a76985e
+8f01009ba75679618cfe8e8e4f40f4dd619b7fe8b5a605a024ae036e37120398b2ed1623bb4429
+2a36ca0d3f55671be59105621db7c5466e720ead9aa4fb552f4ec5a6626ad0c98f328303101595
+c95b30946603b8e240c10161128c0ffcd78a25cf17da6f55997f608d76ce283f6720d448570787
+a53d4ab5b135c198c0ff36059c8902efefe64307497ab5a01598a0d9af941709f6dc08c71e0a92
+087627568a02270e8126416aa659e4e1d07c795e489475ade52594a6a10649f3d6dbc54f218b2a
+4b339d5109c74087fbd4e9246b56d54d35788c4a44f167d5f28a5e00730ad62b780772f58f33e9
+ebed94438f6ff7e7a554a665e7ac613b68b4bfaf31e5a5788246e7fb1adf9710dbdd35e21d82fc
+f9bf66fe88caa7a5249e5232a56259f7b733d179a59988bdd8c4212128b47c13e12c345140c004
+171333b49dcc37c3f0e533b180ccebafc0135acda71c1c0ec667a9d873b845286f4327b1132f76
+90e383cbd825210a7d3b404e1246c48f70e67bf87aba9414543051d68c94174bce8e97f2a6719f
+485a5f8ba462b4b9496a7160797ba6b307a10eb694021b14ee4d714239fdfd3e1d7f8470ee4438
+b2fcfcf7152b2bd6dc261d7ea5a48b82308a039220df8b2c84831443f9771d04fbc6b11d618f44
+d6cb936e2ef8c0babf9614ca0a9f88f723d5ff1bc47b5eb4bd1bb4db0aceac6659d78cdf01dc7d
+a580a72ea45ae8c6c8f28300cefbcc44a1094327c9029bc4a1ac412f0f383ca48e96f58398abe3
+ec998b4d9aa5be971117259e13c2e5976428b6d3041133b303e211d7b5c29b62d35765c100d19d
+6bcc974fff1cf1bd2f9ffe7d8612a39ae90135c55df546f6c471e8d94910a3d8c25037d3d04711
+f15c445c07e3240ea2c4c9247b3a0bdf670f4ceec69eaebd64bc6b4bf5deb4cc91402b2a2f07be
+6b390176436f046a60c9d65a09fda9f41fda8abfa3ddf14ad164b82e256aaa93d41c44b722d2f7
+e9817df03f000000ffff0300504b0304140006000800000021005a9d3795690500006715000021
+0000007070742f736c6964654c61796f7574732f736c6964654c61796f7574332e786d6ccc58dd
+6edb3614be1fb077103460778c259212a9ac4ea13f6ec3b2b458ba0750243a16aabf51b4eba428
+d037d9736cd85ddfa44f3292926ca749336f6b82dc98147578f89df37da40efdecf9a6aeac3517
+7dd93673db3d726c8b37795b94cde5dcfef51503d4b67a99354556b50d9fdb57bcb79f9f7cfdd5
+b3eeb8af8ad3ecaa5d494bf968fae36c6e2fa5ec8e67b33e5ff23aeb8fda8e37eadda2157526d5
+a3b89c15227ba37cd7d50c3a8e3fabb3b2b1c7f9e290f9ed6251e63c69f355cd1b393811bccaa4
+c2df2fcbae9fbc758778eb04ef951b33fb262479d5a9687b9effc0b3c2b68ca158ab21d73e51b1
+e7e755613559ad06c20bb540534ad9836fbfd984df7df8eb42a5335f8a72218d6ddfbd129ceb5e
+b3fe5e74e7dd4b615c9cad5f0aab2cb4cbd1953d1b5f8c66e6b1599bceec93e99753373bde2c44
+ad5b951b6b33b7158557fa77a6c7f8465af93098ef46f3e58b3b6cf3657a87f56c5a60b6b7a88e
+6a00773b1c3885f3aa94bcb274c20c8ed35e4e8856a29cdb6f19839197320c98ea01ec44184429
+0e008388a690b01822ff9d9eedfac7b9e086a51f8b496dae7f8be1bacc45dbb70b7994b7f52895
+49718a5c178fe46a946f03274843c808086948010e68080296ba2075621c45288e100edf8d0950
+98a7d644311be31d039f88e8bbd3367fdd5b4dab88d2bc0ebc6d2d063275db2d4785c952567cb4
+1b5e9ace2ecb77524c914bbd813b97380141f426dbaee3b99eef8c3442ea4182c8a7640ebebb63
+b989dae24a4fbf50ad22316bf265ab76e3c5e0b4eae5b9bcaab8e9af2b778454f0c52fcab8bf9e
+db6aa5492a5b03dddf9bd8e91f334fa84955a68f978283241dd69027462c8a44c9c5b043ad6225
+f2a5f55355e6af79635df04c5c7065d468d7031dc3329d89668ac20476bf40d156a02a5f9d3a3b
+ae9759a5d6b5e013952a8b13163a29017e922025558f8288520248801d88433f42943dbc54b53a
+3420adafffa358ecd100fbe83ec5ba9ee3b8f460c57e4ea6569d8953739a954da1ce79dd35b356
+67ea636666eda918626778ddb75559b0b2aacc83268cc795b0d659a5f6eb6638cf64d9c8618478
+3bf56f8d87a79d9fd9b4d2cd4d62ba7087147b04ea1c1c04572ffb587035c6112edac10d5cac73
+76105c973e225c8d71848b77705d445c23b183f06acbc7c2ab418e78bd3dbc14529db5a7875783
+1cf1fa3bbc1052f325787a7835c8112fd9c34b303a78bb3d2a5e0d72c44b777835d8c3f7db63e2
+d52047bcc11e5edf234f73bf69907797281abd32d8d6c4f7952cccd429eb5654d9a5aa500ade5b
+baa2188a98fe4b562c78aa58924caeea7ebf66414fb466a129f63c184090f8240618c708049051
+405ce27a8cc42c26f1c3d72c85b48dba54b21653ed32c8e5b3c58bb974dd5b619807a39685ba05
+0e970914c358d5610011c600f658000202294071103212e294f8f8dd74ab2c32c9655973565eae
+047fb1d2d7c4db22b3fa5ac615cf9aad16e589eb1f39e848a59aee24a53018de9be2652632bd9d
+3e91ea7f119c37098ead3efc7ecdcb8a37fba2c34f55743e4969e0b8c0f1824415ca410828a38a
+15e4e3044192423f7878d12da41854f7db2a132a5d93f0fea16afe37c2fbb26cfb5bb6d599c99b
+6655d75cdc20dc7ba284c328f270927a2056ab011cba0e0854110d62c7f5a0e3d3d071d0c313de
+57c5d9aabe9373f800874d9226c44f990ada478152394b4104931830278594f9ccf3dc607bd8f4
+ea2bc815a3079f311fdfff71268e3ebefff30b1c31a699fefd9af26e7aa37aa228f0614c2310b9
+589d9b494040c87c0f300fa94f4644c318a55a3d9d8b6fab470d1ea69eae7dc345d796e60f43d7
+190564ea079fb808a99be744f320921d58cdfcb90e5fb595f839eb5eac8d4a868f7c6c863aadcc
+c17467a2439ffe203df91b0000ffff0300504b0304140006000800000021008f55c3fd73040000
+6b0f0000210000007070742f736c6964654c61796f7574732f736c6964654c61796f7574322e78
+6d6ccc97cb6ee3361486f705fa0e82f6b42ea46ec63803dd580c9a26419376d11d23d1b13aba95
+a21c3b8300f3267d8e16ddcd9bcc9394a4a4783249334ee100d998147578780effefd0d49bb79b
+aad4d6947545532f746b66ea1aadb3262feaab85fecb0506beae759cd439299b9a2ef42dedf4b7
+47df7ff7a69d77657e4cb64dcf35e1a3eee664a1af386fe786d1652b5a916ed6b4b416ef960dab
+08178feccac819b916beabd2b04dd3352a52d4fa389fed33bf592e8b8c264dd657b4e68313464b
+c245fcddaa68bbc95bbb8fb796d14eb851b3ef87c4b7adc8b6b9fc5dd794115b8b474b3f127967
+e765aed5a412031705a7a5d6d7b9f6ae5e9192abf75d7bc12895bd7afd036bcfdb33a6a69daccf
+9856e4d2cd385d37c617a3997aacd7aa637c35fd6aea92f966c92ad98abdd0360b5d48b695bf86
+1ca31bae65c360b61bcd56a78fd866abf4116b635ac0f8625199d510dcc374ec299d6137e426a9
+388e3b3e45d4b362a17fc0d88e9c142380450f203342204a5100b00dfdd4f6706c43f756ceb6dc
+79c6a852e55d3ed165b90f14ad8a8c355db3e4b3aca9463426c28498161ac594517e883c2f347d
+b11cb42c0ba008a520401001c7b2133f08a06de1e476dc0011f3d4aa2c8c31df31f14988ae3d6e
+b2f79d56374228a9eba0db9dc520a66cdbd548142f784947bbe1a5eaec7679a4806fa226dfca45
+2e45ab06c9bcecf839df96543db4f24785c184102591059b5390a483b8fc48c921b689533630af
+e53dcb56da8f6591bda7b5764909bba4c2a896a90e09cb78946b6317823189ffdf08c00981a10c
+ba5614e48dec51a6d9af940798fac8775d045ccb0b01421602611407c00c4de85808c7d88a5e92
+8722dfec4c0e80422b29589777d5fd141a58f1b06e5849ae040939edb40b91db004bf734195f2f
+a752787ab9dfaea5332dbda435ddc3a3fd6d8f092bf8333cc26f7bfcb5a0ec191ed11e9bfce99f
+7af984cbe795189a4a2c21bcafee55187ca51516c756e8413b06a68b20405e68c91337023849d3
+c8f73c1198f3f2276ecec50de6466442caa50c4c56ddf0477790b25b8acb80ca3680b11dbb1104
+d0c31820070720f06c1fc03808b117a2d473d1ed74b1c809a7bca8282eae7a464f7b7973780892
+d6553c2e29a9ef8a9a1f59eecc8433b1d5fe0e291183d2bdcecf08233f3fc4f1ff00e74cc0e1fe
+d39f37b42869fd2574e89542e7d911b41cc19b87a138d671e08330767d90402f753d1cd85e18be
+3c744bce06eafee8893856d804de01cffbc3aaeddea9dd9405adebbeaa28bb27b8f34a054fa3c4
+09fdd403293463807cc7017e8421b0a1679a711a24317ad1fff14170f13174d2578f6aaefece0e
+7cd82469e2b9297640ecc200a000a720b293186033b57dec62c7b182bbc3a62b8b9c0a45f73e63
+3e7ffceb84cd3e7ffcfb00478c6aa60fa269df556fa4278a02d78efd0844e2d20550127820c4ae
+03b003118a233f8c612ae9692df4901e31b81f3d6d734d59db14ea9bd1324780d6445e0ea0e740
+cbf6dd60146aa06417ad94fe5ce62fda92fd44dad3b5c264b82ec56aa895680ea63b1399fbf491
+7cf42f000000ffff0300504b0304140006000800000021007555dfd22405000070120000210000
+007070742f736c6964654c61796f7574732f736c6964654c61796f7574312e786d6ccc585d6edc
+36107e2fd03b087aa75724254a32b20ef45b14759ca0760e204b5caf10fd95a236768200b949cf
+d1bef62639498794e4ddb59dd48ee3c22f4b8a1a7e9c99efd368b42f5e5ed695b1e1a22fdb6669
+e203cb347893b745d95c2ccdb76729f24ca39759536455dbf0a579c57bf3e5d1cf3fbde80efbaa
+38ceaeda411a80d1f487d9d25c4bd91d2e167dbee675d61fb41d6fe0deaa157526e1525c2c0a91
+bd07ecba5a10cb628b3a2b1b73da2feeb3bf5dadca9cc76d3ed4bc912388e05526c1ff7e5d76fd
+8cd6dd07ad13bc0718bd7bdf2579d541b4b29415370d6d2636b080cd23883c3fad0aa3c96a5838
+2b2507c8aae4fa4edf9d09ced5acd9fc22bad3ee8dd01b4e366f8451160a60da682ea61b9399be
+6c367ab2b8b1fd629e6687972b51ab11f2605c2e4da0eb4afd2ed41abf94463e2ee6dbd57cfdfa
+0edb7c9ddc61bd980f58ec1caaa21a9dbb1d0e99c3d17930547ab41fc7bd9c3d1a44b9343fa629
+099d24b5510a33645ba18dc2c4f6514aa89710378d08659fd46ecc0e73c13523bf16b3b230bbc5
+665de6a2eddb953cc8db7a92c5ac2e2012db1391cacb8f0e0b284eb185ec2081d3632f4681eb07
+08278e1746961fa781ff694a00f83c8f3a8ac514ef14f84c44df1db7f9bbde685a204af13af276
+6d3192a9c66e3da92997e24c0b6aa658ddd7936da2ef64193bc4b6ac913f8c09a48aee33ee637b
+34504c42465d66dde273c4ee0ee565d816576af7398cc063d6e4eb161ebef311b3eae5a9bcaab8
+9e6f2adc2993eaa2d1fe6b7e0bbefa1d16fb0f4b93a953c78326db71be83d1a91f1d95804d55a6
+0a4bc1519c8cc7c9232d1da05472313e9b4631887c6dfc5695f93bde18e73c13e71c8c1a053d92
+331ed3e9c0e680748cdf962b9de5fab681d3a4d62c79a69ab580c6c4c30c8561ec233bf2521452
+27425ee87b0e75a81579f1d36bb61fce47cd82534a898fd22e651681b0bea15dcc1cc765e4beda
+fdaa60eb4c1cebd256360514783ddd17f1f970022f340db0a367e5eb4d3deb29d9a2da8e4b94bf
+0f85de7b5414de044db7d0632e1e0c8dbd5d68853741db5b684c5dacaac283b1b7a564029cb09d
+1d6c8f78ca85c7612bc0099b6db109f17491791cb6029cb0dd1d6cd7a6df43e53eb6029cb0bd2d
+b602fe2e2ef7b015e084edef60334757f8c7612bc08757eb5497e84d2baaec821b05ef8d6d2d1d
+8b78ff74f5db9eeb779cc9a1ee3be8fb3eacb30a0e35e8736d3d0296604a020437e074cf2128f0
+43e83f1c4282d00ebcc0c24f5fc60b696a0540b25673291fa5f0d55aae1bd26f165c7da105b382
+7e5847ebd388442ca488ba698a6c27f591ef120fd1c80f5237b01397d99fe6eebac8249765cdd3
+f26210fcf5203585377567f4b58c2a9e35d7bdab3cc2ecc0a20790516f2b29f041f3de146f3291
+29c9df50eff708ce9905970efffcf98197156f7645673f53d179d4b269101114474182ec1094e7
+63df8544441676ec942651f8f4a25b4131d2aafb63c804a46b16de7f34110f11de8f659b5db3ad
+3ee89a66a86b2ef608779e29e1984531096d07311cc0578e87e1c3dd497ce47a8cba21745dcc0b
+fe8766b12a4e86fa4ecec796eec7169b38895d96a40e8a18850ed94f1314923842a995102f65a9
+e360ffbad8f45509ef4af0eebe35e6cbe7bf4ec4c197cf7fff8012a387f99f8139ef7a36a9270c
+7d46222f4421b6a16ec6f0ac06297350ea50db8e422f8868a2d4d361fbb67a60f17eeae9daf75c
+746da9ff38c1d624a04d56e9f69012c6089b791e55b2f556517faae287b112afb2eef546cb647c
+e7477aa953d21c4db7262af6f99fa2a37f010000ffff0300504b030414000600080000002100fd
+00fcd1320800004e360000210000007070742f736c6964654d6173746572732f736c6964654d61
+73746572312e786d6cec5bdd6ee33616be5fa0ef20f8b6502c8ad49f314e61495677b0e93468a6
+7bb177b444dbdae86f293a93a41860de64817d8b5dec5ddf649ea4879464cb49ec49da49e10446
+008b3a3ca20ecf77bec343da79f3dd759e69578cd769598c07e8c41868ac88cb242d16e3c1cfef
+23dd1d68b5a04542b3b260e3c10dab07df9d7ef39737d5a8ce921f682d18d7608ca21ed1f16029
+44351a0eeb78c9725a9f94152ba06f5ef29c0ab8e58b61c2e907183bcf86a661d8c39ca6c5a07d
+9e3fe6f9723e4f631696f12a67856806e12ca302ecaf97695577a3558f19ade2ac8661d4d35b26
+9dc2fce28b2c91d7d9a2f9fc89cdb534b9062f1906020d3a5223b320e3da15cdc683d9020d86a7
+6f86ad72db920fd7d57bce986c1557dff3eaa23ae7ea0defaece398c09430eb482e6e05f3980ea
+68d5d46d71a51ac33b8f2fba261d5dcf792eafe01e0d2c04146fe4e750cad8b5d0e246186fa4f1
+f2c70774e3e5f401ed61f78261efa572568d71f7a76376d3799f0a965500cfed926632541ac781
+4967b5e88c5bf1743cf8258a4cdf9a46448fa0a513c327ba3f259e1e99d89d9a4e1498d8fe289f
+46f628e64c61f636e9620fd9f7f0ced39897753917277199b781d3c51f408d481b7dd2e05f0c02
+12ec06fa04598e4e42c3d43dcb413af61cc3833e9f38e863eb0bb0b9bbaa590cdba9b73ee830a9
+abb332beacb5a204cc24c40d846b8d065779ad969ab8a9c05d2215196bf59a4ed5d838fc41b45d
+ec42e42a18b16d21d3dac61d1916b26ca9200145d8b42c1b6fc14a4715afc5f7accc35d9180f38
+8b85028a5ec10c1bd54e45d9d458528dc4b55f263752730657401f52093cbf2cf9ed40cbde16f5
+78e02142e0dd42dd10cb31e186f77b665b3d220bca4c851f2d6218673c880557b61440dcc94a94
+f3b4b5a879a5ecca6a71216e32a6e65dc90f25e660504665264b981e4e1bb788531594b94a5d4d
+32d092158f97dadfb234be6485366394cf182815f22d0dd6120a35f4703369e587fd44c06b2200
+1a7d1e9807ca83c8987a7e3835f48937011e20043c70ac896e637bea19fed4c7f84fe08144561a
+24a3f78fd001b9a665efe703c116c2d83d7c3e3c9902958cfe2bf5ac12eea344a4787055f28c2e
+800109ab3519b10d49eafd8cb8fb3a85d8fed7fde3831c4c9bce58c11e31a2f9e511439e8a278c
+a8f2dffe11ff9e02748f1f913cc2c9bffebf98ef19f269a98574a925a46295d7fde4820f34b9b8
+51e8987e38d1dd20243a71609175c308e961141ac83203c341c6f327974440497b0b33a1d9bc4d
+322ac07e6f92b131aca7d69d62cb7408560a32c76c56e517b4e4aae9745945b5af3224c39d660b
+d82a64cad884cd7f0291742792d3559094599a4469963d50228beba6001469211a896319465764
+ae959bbbcd38c3ee4daad91ad2b47b062a42ceb3a409360f076660fb58c74e14e9c48a3c58c94c
+57c78137899c09993a36f938e862820a26d29c45e962c5d98fab068abb3cd6ea5c0419a3c53aa7
+8a53649f18f80422dddd307a2e370e100b45724e39950eba930d7e0fdfad8eefd1ead77fdfb234
+63459ff3e440391f460176d104eb6138f17462bb13ddf3ac00aa6b0ff9aee1d8beed3c3fe7e710
+d02a4affb5a290d579cbfba60c7e0aef89815d553bec223e944cc47dcdc4efcaf1c3a3fed7e59b
+bde61b18c38a6295e78c6f51ce3a50ca99d3c09cb88ea54f43076af86812c95dadab47641ad941
+e4e1107bcf4fb93a4bdeadf28758a74aa5a7adb63632f6b2eed52fb787cab9f5721b42b0d9d3c8
+d2031b439ef7a2a9ee9b61a0c386d274233bb22ce4ad97db1a5ec580518f5e653f7ffaef3b7ef2
+f9d3ffbec222ab2edd795c17f7aad5b2d7f73ddb0c5c5ff71181ca21f41c7d12d9961e599890c0
+7727019e4af65688dc672f081fc7deaafcc07855a6ea1413192d811548d8c1c842aee3364829db
+baeb9aa5ede9649cf11f68a5cd16086a3281c0c3d7d04a2ea1355b9852664a992965d0a271cc0a
+011a6da393989d64ad833b09ee24a493904e627512ab93d89d04d2e7324b8b4b7086bc0cb47999
+fdb51174ade6ac13f2c419bd2957e26dd222d19334a7898838c4c536f1803d2329e16f13958276
+eb5a92699dae2aeff7e8a29eae2a09f6e89a3d5d95c8f6e8e29eaeca477b74494fd7fe82aed5d3
+75bea06bf774d529c71e5da7a7eb7d41d7ed63a1e2748ff21670dde2711f7871ad924baddaf228
+74e7de4383fcf49ece2e6edb1cdbe4559554193d2b7c7ea9ced4e5f702457b0b5d4b4810b0609e
+af8a58c87e35727151c5cd12179fc76d96f48c4d96ec2bf8f2547f5b759d4cd7bdb3d5bbb268ce
+617af9ba31f2124a8827e4ee76e8be969a924aa3731a432afd36ffa79e897635a4773a186d8ff5
+eb3b1d71dd8efd609edff67ea556be7b50e4949f01c466530ea705247470aade090e07295137aa
+a8b7f2f5c08a4a581b37de99f09482d5152dca1a6e0dd3f0a1f42070edfe80a9552ae26544f334
+93e50608e225e53513eb156bb60a40a2c4e3c1e74fff69a4bd7030d51ee139c2a1d8150ec5ae70
+28f687836a9a1bc86dd752c6bf00c8ad4342fcd912c057445cc2dc228e3788c396164b9f1f217f
+22e4ca69070eb9c4b9859cf4200778d586ea08f99320472f21af4b9c5bc8adde526e588e82f108
+f9eb835ce2dc426ef720b7107929e5db11f227422e716e21777a907b4e63fd11f2d707b9c4b985
+dcdd408e89299d7e84fc35422e716e21f77a90bbae7d2cdf5e29e412e7e6c7a59b73996a548a25
+e3eb531a78e2bc098c7676f70fc7372adb473acf12242fcdc70f1f7da8af708efed97950d039e1
+e89f1dbb6aecc88df5d141bbf6a0c8355d65fdd1413b766c6a193f3a68f7fea6fb25c0d1413b76
+0360ee3149efab9d6dcb3926e9ed4ab35f5caa5f54745fd436dfe336ff0776fa1b000000ffff03
+00504b0304140006000800000021009119fff8d404000095130000210000007070742f736c6964
+654c61796f7574732f736c6964654c61796f7574342e786d6cec58cd6edc3610be17e83b08bad3
+12c51f4946ec407f2c823ab651bb3df4464b5caf1afd95e2aed70e02e44dfa1c2d7acb9be4494a
+512b3bfe89bd0eecc2875c9614351cceccf7cd7056af5eafeaca5a0ad9976db363c32dd7b64493
+b745d99ceed8bf1e3310d856af7853f0aa6dc48e7d2e7afbf5ee8f3fbceab6fbaad8e3e7ed4259
+5a47d36ff31d7bae54b7ed387d3e1735efb7da4e34faddac953557fa519e3a85e4675a775d399e
+eb52a7e66563aff7cb4df6b7b359998bb4cd17b568d4a8448a8a2b6d7f3f2fbb7ed2d66da2ad93
+a2d76acceeeb26a9f34e7babceda83933f6ccbc8c9a55e81f6ae763d3faa0aabe1b55ef8fd4c94
+d69b66ce2b25ccbbbe3b96420cb366f993ec8eba4369b6ec2f0fa55516838af556db59bf588b99
+c7666926ce8deda7d3946faf66b21e461d0a6bb5636bc4ce875f6758132b65e5e3627eb59acf0f
+ee90cde7d91dd2ce7480f3c5a18357a371b7ddf126778e4b252a6b0890b163af5793450b59eed8
+ef19f36292310c989e01ecc618c4190e01f35090793e4b3c443f0cbb21ddcea530a0bc29267241
+7a0bd0bacc65dbb733b595b7f59a1913c1349610afb11cac7cefa1183237202088620470865210
+bb24004118c208277e18607dfa18006df3341a2f9cb5bf6bc72720fa6eafcddff556d36aa0065c
+47dc2e25463087b19b4f842a5525d672e34b33b98af29a056a15b7c5f970c8891ecd22dfae7a75
+a4ce2b611ebae1c798213510151ff2b51020cd4670d5ae81438749093952de2a16329f5b3f5765
+fe4e34d689e0f24468a16670757478b0c7a876ae4c7026f0bf4e01345160cc83bed3f978613242
+5ade0be5038c538203e6034ab208e0388e4018bb21486106634218826ef09c7ce82fb4fdbc9a0d
+e6acae84bf428a3bf23e4081ae5726a161e011ea91eb2580c000d24160486d8c084428b899e0a3
+ea8de9d60d4c5b569715e43efa31c3b9652b2b7eaad95688de3ad6a68d84ecef67dfcde34c70ee
+3f6e28c34a58d98968c4061abd8735a6b2548fd0881ed6f85b29e42334e20d82fce9df66768fca
+c7a531be278dd10b4de334630451cf07098b438051e283288d5d00094efd308a8298c0ff318d0d
+af1e95c614fadef73cfe9ec74f98c764cae394ab457d2d8df14b4de3240903162720a121031827
+09885c9602142628a409832979d6db78ecce0a65dfba97c7a6f849bab599fed360bc0d51e22554
+b7a1c867da5bc24210fa5e00501246cc8f70e653fc61fa0f52702554590b569e2ea438582803e1
+4d22597dad924af0e632a9d52ea45b2edad2a10eae28a56d30b837c52197fc97db74fc16c2d189
+706cf1e9af0b5156a2f99274e485920e27a18722ea812c2110e0845010c591b683119f309f86c4
+45cf4fba999223ebfe5c705d56e444bc073ac2c710ef69d1f62fd16eab5234cda2ae85bc06387d
+a1805314e90b9465002601d655c6d55526f07d90519cc5888698f9f8f901efab627f51df89f903
+edc337159b344b7daabb245d5a91ee9042ed7eeca509606ee6058c32426078596cfaaa2c844674
+e31af3f9e3dffb72ebf3c77f9ea0c49861fa7832c5ddccd6ec89e3907a49108318625d37d35037
+7b8c12a05b407d65c44194a06c604f07f16df6e8c5cdd8d3b56742766d693e2f41774da025d757
+798811428442d3a239c6b469bc24c9d1e0be1e2bf99677074bc392b15b4acc5237307314bd1219
+5c9f3ea7edfe070000ffff0300504b030414000600080000002100d60634cc2e060000371f0000
+210000007070742f736c6964654c61796f7574732f736c6964654c61796f7574352e786d6cec59
+cb6edc3614dd17e83f08b3a747a4288a3462077ab108eada41ed66d19d2c713c6af42aa519db09
+02e44ffa1d2dbacb9fe44b4a529267fcccd8890303f5664449e4e125cfb94777a4172fcfcac25a
+0ad9e675b533815bf6c412555a677975b233f9ed88033ab1da2ea9b2a4a82bb1333917ede4e5ee
+8f3fbc68b6db22db4bceeb4567298caadd4e7626f3ae6bb6a7d3369d8b3269b7ea4654eadeac96
+65d2a9537932cd6472aab0cb628a6c9b4ccb24af26c378b9c9f87a36cb5311d5e9a21455d78348
+51249d8abf9de74d3ba2359ba03552b40ac68cbe1c5277dea8d576a7f5d1d9d1697d70fcc7c432
+9de5525d86935db5fef4b0c8ac2a29d58537429e14224fe7e646db1c492174ab5afe249bc3e6b5
+34fdf797afa595677afc306e321d6e0cddcc69b5348de995e1276333d93e9bc9521fd56658673b
+13c5d9b9fe9dea6be2acb3d2fe62baba9ace0f6ee89bcee31b7a4fc709a66b93ea55f5c15d5f0e
+1a97739477a2b0f4ee9838f6da6e8c6821f39dc97bce51e0c61c03ae5a00db0106418c19e0c8a1
+31f278881cf2418f86643b95c2d0f22a1be505c9354acb3c95755bcfbaadb42e076d8c12536c42
+3cb0a9a37c6fc7761cb00082d0836a76e80680da3e073ef5380b2881ccf63e0c1ba0621e8f6615
+d361bdc3c24722da66af4edfb656552ba234af3d6f173d7a32f5b1998f92cabb420cfdfa9ba6b1
+dae51b29a60ef32835dc39c485c8bd4c36b45de8127b60113ac875897395cb1ebad9eece823a3b
+d7c38fd5d1682dd92edaeeb03b2f843969f48f09432a8a8b447b41264014f7b376bb8668454027
+649f4e56b690e9dcfab9c8d3b7a2b28e45228f85ea54e908faadd42b35d0d3550826aabbc5e55c
+884b2db65189fe6e9e146a5e0b3d519985d4269e1fc4c0b5a31860eedb80c55e08a807b14f5d14
+b0103ebecc34b53a202d8eaf511b2414c25e4b2bb929b1791ef57ab551e4308836159b9554e9bc
+56567fdc438eba33ed6501d530ab4ce49eb1a4bcca943beba60158ecab4790199589d9afaa63fb
+4e990fd6b23f1e9779813200a21520763da4fb6e846a5f47d55003aab34265109b08364185f43a
+aa861a50f10a153a1e34f9bc11ace9791956630db0ee1a2c45d4c4f050588d35c092152c429498
+0d7b28acc61a60bd35580f3b1b337613acc61a60e90a56636e4ed90db01a6b80656bb0c4f5be8a
+328dd5b7d772c258b19e4475b8786edf65cddcf8f1b2964572a29c3813ada59db337ebf65b3a33
+1e9df955a52db95d3767e7899a332411839451c0b0e303ecb904042a0680a94b239bd98807fc31
+cd5973afb6683658736f9b0fb466e4daaeed5da9042e59b343287655efaf2b04be97faae4e6776
+f2eee97e3fd560567c2c2ab101a2d9eebb11239977f7401c1e8c7721bec985bc0722de60933ffd
+5bcdee80bc5f1abbb71558f889e6302621653e0c408c62ac0aacc00581ad0aac08f1904688211b
+45dfabc0d2f9fce7225104cb21a5fbb2fb3e294da087cc63eef6728b3a5027fd73b9f55c6e3d97
+5bffd3728bdc516eb94fd4aa0962b17e5f01108e1d65d53806d471086021b32362f310d2477de5
+72dd9ecde3f5c1f67c4bc9b566cfcf25d773c9f5c554f6c6548e926e515eca64f254ff38453685
+34e2007102010e7004021707c00e2248781c85c4ff0e6fb5b2ae2fb9d6fe42c1fe9df5ad196d5e
+a96f9876b322eb57cb9c1085247080e3710eb0cb19601ea2c00999cf3d1fc71ec11fc68f0459d2
+892e2f05cf4f16521c2c3a43e15521596dd9858548aa8ba4ee7621d9b29d2db5d57425291583e1
+bdca5e2732d10fb02b727c88e0e82838bef8f4d73b9117a25a179df74445e7c754f92d26803387
+011c3355e9fb5005837ddfc5c40e9cc07d7cd1cd3a7953a10fbff05ef53ec2fbb66cb30bb6eb22
+1755b5284b212f114e9fea271a18ba14c608408c6c802971008331040e610ea7be1b70481e9ff0
+b6c8f617e58d9c7fe185cd83cc268a238fc4dc0521d12a673c06018a42c0ed18514eb8eb427661
+366d91ab725745b7a9c77cfef8f7bedcfafcf19f6f6031e6307edb1cf7ddb406f504012328a401
+082056be19310ff89cb880bb0ec66140fdd089b57a1a88afab475ddc4c3d4d7d2a6453e7e6fb2f
+b407012d135d1c104821a29e33d679bd4a56d16aea0ff5fad5b190bf24cdc1d2c8a42f974273a9
+d1d2ecbbaebae8b58f1fbc77ff030000ffff0300504b030414000600080000002100ccacc02fe8
+030000060c0000210000007070742f736c6964654c61796f7574732f736c6964654c61796f7574
+362e786d6ccc965d6edc3610c7df0bf40e82deb99228ea6b9175a02f16455ddba8dd03d012d72b
+445fa5a88dd74180dca4e7685f7b939ca4434af23ab10b18850df8654991437266fe3fcef2ddfb
+dba636f65c0c55d76e4c67659b066f8baeacda9b8df9fb1545a1690c92b525abbb966fcc031fcc
+f7273ffef0ae5f0f7579ca0edd280dd8a31dd66c63eea4ecd79635143bdeb061d5f5bc85b96d27
+1a26e153dc58a5601f61efa6b6b06dfb56c3aad69cd78be7acefb6dbaae059578c0d6fe5b489e0
+3593e0ffb0abfa61d9ad7fce6ebde0036ca3577feb923cf410adac64cdcfdbfa601ada54ec61d0
+314f20fae2b22e8d96353070360ae3aa92bcd613437f253857bd76ff93e82ffb0ba1edcff617c2
+a84ab57e5e675af3c46ca63fdbbdee58df2dbf59ba6c7dbb158d6a2115c6edc604c50eead75263
+fc561ac534581c478bddf913b6c52e7fc2da5a0eb01e1caaa29a9c7b1c0e5ec2d129305476b41f
+a7835c3c1a45b5313f518a132fa70451e82162270425398910c56e98e380a6d8f53fabd58ebf2e
+04d7a2fc5c2e7039fe23419baa10ddd06de5aae89a998c0530d0d221b396cacb4f9e9bb9244e1d
+383df211f1220725419e202fc9529bb84e8629fe3c27007c5e5a1d8535c73b07be0831f4a75df1
+6130da0e8452ba4ebadd5b4c62aab6df3d046ab69b2675e798e59902799b74e5411d720dad1e64
+eb7a9097f25073fdd1ab1fed8600216aa6ee6bc951964fe2ca132d07a4497231216f94a32876c6
+2f75557ce0ad71cd99b8e660d4aa50a780953f7a6bebe882b588ffdf08b80b0219936333f4701d
+ef76ac86930dfc4671080312e0cc0951846984484a429424294636f5e20c7b180711797d1c4a09
+d5f50e2261f556390677d1996ee18be0b18512a5a38ddc14a77ee22237a014e08790a30087c84d
+a3980631c9031fa25d9c6292cbaae1b4ba19053f1fa596f07bca8ca19169cd597b5f4fe489e3af
+6c7705a90e8f48810f5af7b6bc6082fdf698d5ff031c5980a3e33f7fdef1aae6ed43e8dc370a9d
+9f7a4ee48514e511f046803314274184322ff0314eb06be3e4f5a1db4a3151f7c7c804a46b016f
+59fb02e0bdacdadebdda5d5df1b61d9b868b6f04276f54f028a7d48b888f704c1d440212a3d84e
+63e4e7506c6896789e475f5f7078a89d8dcd939ae3572836599e057e4e3d94fa2e94d688e628c1
+598aa89de390fad4834b705f6c86ba2a3928faec1af3f5cb5f6762f5f5cbdf2f506274b3bcd696
+bcebde4c4f92443e4ec304250e81ba9945018aa9ef21eab984a44918a76eaee8e91df2981e187c
+1e3d7df7918bbeabf47bd6b16780f6acde98010e5cecfb6130eb3441727456297fa9c287b616bf
+b2fe7caf2999fef7533dd42b3227d3a3890a7d79bf9ffc0b0000ffff0300504b03041400060008
+00000021005632cb5c8e030000fa090000210000007070742f736c6964654c61796f7574732f73
+6c6964654c61796f7574372e786d6ccc56db6edc36107d2fd07f10f4ce952851b745d6c1eac2a2
+806b1b75fa018cc4f50ad185a5a88dd78181fc49bfa37ded9fe44b3aa4a47512bb801f6c202fe2
+6834339c33e788d29bb7b76d631db81ceabedbd878e5da16efcabeaabb9b8dfdc73b8a62db1a14
+eb2ad6f41ddfd8473ed86fcf7efee98d580f4d75ce8efda82ca8d10d6bb6b1f74a89b5e30ce59e
+b76c58f58277f06cd7cb9629b895374e25d947a8dd368ee7baa1d3b2bab3e77cf99cfc7eb7ab4b
+9ef7e5d8f24e4d45246f9882fe877d2d86a59a784e3521f900654cf6b72da9a300b4ef1bd67db0
+2d13260fe0c0f619202faf9bcaea580b8e73cea5f10de29de45c5bdde11729aec59534a117872b
+69d5954e9d536c677e308799dbee600ce7bbf49bc564ebdb9d6cf50a13b06e37361075d45747fb
+f8adb2cac9593e78cbfde513b1e5be7822da593670beda54a39a9a7b0cc75be0e44c8ded208082
+bb3d6b1497961e92e9e97c504b77a3ac37f6274abd34282841142c44dc94a0b42009a29e1f175e
+4433cf0fef75360ed7a5e486975fab455f387cc4695b97b21ffa9d5a957d3b8b63d118d089c94c
+a7eef893efe55b9ce42e0a039c21e247054a709ea2304db334247980497c3f0f037a5e5683c299
+b1cf43584819c4795f7e18acae07d234c71387a7888958bd8afdaca94ac11b75074858b3d38d01
+1178a2600936c60303b342d46dda5747bde97b588d93ad9b415dab63c3cd8dd0971d48d3a04dfc
+cccbc2d4477e442922014d50127931f2b3644ba32d29a290dc2f42af98e2aa6e39ad6f46c92f47
+652894c035bc017012541ce505f4ddaaace1ac3b89499de170e5fa2b1875acc7350d0d7a30bc77
+d51593ecf7efaa4c031606e702ca59a4f6ff82f317c1d1f1dfbfee78ddf0ee6bd1793faae870e6
+82dc02443105d181c6509283951152b884d028f5ddd717dd4ec949757f8e4cc2b816e12db92f20
+bc97659b9cd8ee9b9a77ddd8b65c7e43b8ff83125e64dbc0755d0f45599cc0ee31415b976e5192
+6e53d7a52e2952fafa84c3c7f9626c9fe4dc7b85c3262ff2282c6880b2d007d0092d50eae519a2
+6ee1c534a4418093d361333475c581d1679f315f3eff7d21575f3efff302478c59964ff5327763
+cdea49d324f4b238452926706ee64984b63484f737f009c9d2789bf985568fc0e4b17ac0f93cf5
+88fe2397a2afcd3f0c7667011d58b3b163cfc7d88b4f3c4d22796856337fade1c3dac8df98b83c
+1895c05ec072665c422b730a7d08d1d0977fb6b3ff000000ffff0300504b030414000600080000
+0021004ba90907dd05000065170000210000007070742f736c6964654c61796f7574732f736c69
+64654c61796f7574382e786d6ccc58dd6edb3618bd1fb077107ccf58147f44054d0afd0ec5b2b4
+58b35dec4e91e858abfe46d1aed3a2401f64c09e63c3eefa267d92919494384e6a3b6983e5c6fa
+241f1ef2e3777848e9d9f355555a4b2ebaa2a98f26f0c09e58bcce9abca82f8e26bf9c25804dac
+4ea6759e964dcd8f2697bc9b3c3ffefebb67ed6157e627e965b39096e2a8bbc3f4683297b23d9c
+4ebb6cceabb43b685a5eabff668da852a96ec5c53417e95bc55d9553c7b6e9b44a8b7a32b417fb
+b46f66b322e351932d2a5ecb9e44f032956afcddbc68bb91addd87ad15bc5334a6f5cd21c9cb56
+65db9cff7eb69a58062696ea019c1cabccb3d7656ed569a51ebca8e76929adaa90d6a73fcfd53c
+667351cca48175ed99e05c47f5f207d1be6e5f09d3fa74f94a5845aed90696c974f8638099db7a
+6982e946f38b314c0f573351e9ab9a146b753451b5bbd4bf53fd8cafa495f50fb3eba7d9fce51d
+d86c1edf819e8e1d4cd73ad559f583bb9d8e33a67356485e5a7aaecc384e3a398e68218aa3c9fb
+247102122718242a02d80e300862ec81c4412c76dc247410fda05b437a98096ecaf3221f6506e9
+add25645269aae99c983aca9068d8c5253558578a8aa1ee57b4451e8138a419c7821c01123c0f3
+690430756c1af8ae8d08fc304c801af37835594c877c87c4c74274ed4993bde9acba5185d275ed
+eb7685e88ba9afed7c90962c64c9075cffa709ae67f9ce1233e4b98c99da61e22abdde2c36f290
+e320b72f22a4b63d20d64bd933b787721534f9a56e7daeaeaa84699dcd1bb508cf7bceb293afe5
+65c94dbc2ce130a09ccf7e56e0ee9deaed9afd0aa0e3b586adfe31ed846a54a6da55720ea2b8ef
+431e1ba9a8124a2efa8569e50b91cdad1fcb227bc36beb9ca7e29c2b50ada9fb62f4ddb4269b31
+0b93d87679a2519efd9aed5ae51aef74c485e53c51ad629220db097d90b82c0038f12960ae4b40
+ecfbd40f3c27b4fde031b55ae4ab6bc8fe3225902138e8d4632e76c84d9d52e83a5a3c46a798b9
+88f6887d74fa15e234a1731bebb075ec085021ba038bd7b1234085f80eacbd8e1d012a24bbb023
+408574177604a8d0dd851d012a64bbb0234085de2e6c0fb86bf1b77add2fcbabbd669b1924c601
+968d28d30bb5f673de59674a32bd3d74dbbd60b33b23daedddfdf6569359f139aff91e8cce6ec6
+4814f21e8c6837e3af0517f760c47b4cf2a77febd916cafb992abedaf355a1d61d153d51478551
+0423162010464cf5ae364cc0087501c13026288e022f208fbffb6b2b9b9875a4a66ba687b61a04
+f6d0e380631377b0a62f9c0710839028f457faac55a5e2c49c148b3a5787671d9a568b53f58660
+5aadd9843e847cd18607aae124b31fdf0dfbddb0ea81cf8358a3f6e3bbb14d6cd8f9c007916bd2
+d88f709be78f84cc617acb7900e1c6c630103a0ea31af600c28ddd632474b1d9401f40b8b1c50c
+849a6dffa26cdb8746424adc0716e5ffdfaceee7b164f4d828958beac6b9153f5197a5b6134342
+88ea0eaa77ac043210501a8018d9110a023f0ce9a39e5b7b97cde52d8f85bd0ebe68b2e6cd7bab
+159a1ba3965999f7d97a2874544208203749803ab37bc0731d0650e8f989ebe3d8a5f8c3f84d21
+4f259745c593e26221f8cb85fe56705b645657c9b0e4697da545790ce9818d0ed454b36b49a931
+98bad7f9ab54a45aef1b527d88e0e828b864f1e9af77bc2879bd2e3af2545fec632f26ccc300ba
+0155aff328019ee30780529810cf61811fb3c717dd4c8a5e757f2c52757413a3f076bc45dd4778
+dfb6daee55b59bb2e075bda82a2e6e149c3ed182c7a167275ee0e985a6de8eb11f032f8c95d504
+3689f4279e80fa8f5ff0aecc4f17d59d35df71a27b90d94471e4d2382120a4c85307d824068113
+8520b16387253421047a5766d39585da1dd5e8f6f598cf1fff3e15079f3ffef30d2cc65cc64fa0
+e3bc9b68504f1078d40959000288956f469e0bfc84aa4d83208cc380f9218ab57a5a886fab473d
+dc4f3d6df3968bb629cce762680f025aa6fa25d1231e830cd3a14ebd48ae07ab2bff5aa7afaea5
+f8296d5f2e8d4afa4d3e348f5aadcc1e7a0dd1a98f9fc78fff030000ffff0300504b0304140006
+000800000021004a0963b7a105000020170000210000007070742f736c6964654c61796f757473
+2f736c6964654c61796f7574392e786d6ccc585b6edc3614fd2fd03d08f34f8ff892282376307a
+15455d27a8dd05c812c72344af529a899d20401652a0eb687fb393aca49794348fd84ea6ceb8f0
+cf88e25c1ef2f21c1e927af1f2a62cac95546d5e5727137c644f2c59a5759657d72793df2f6324
+2656db2555961475254f26b7b29dbc3cfdf18717cd715b6467c96dbdec2cc0a8dae3e464b2e8ba
+e6783a6dd3852c93f6a86e6405ffcd6b55261dbcaaeb69a692b7805d165362dbceb44cf26a32b4
+57fbb4afe7f33c95619d2e4b59753d889245d2c1f8db45deb4235ab30f5aa3640b30a6f5ee90ba
+db06b26df2f4f266629930b5820a3c3985ccd38b22b3aaa4840a3f87629977d6a73faf6016d385
+cae79d096a9b4b25a52e55ab9f5473d1bc56a6edf9eab5b2f24c630d1893e9f0c710665eab9529
+4cbf687e3d1693e39bb92af513a6c4ba39990073b7fa77aaebe44d67a57d65baa94d17afee894d
+17d13dd1d3b183e956a73aab7e7077d321633a9779270b4bcf9419c759db8d235aaafc64f23e8e
+89cfa398a1184a88d93e437ec43c14132a22e2c601a1ce07dd1a3bc7a992869c9fb35164d8b943
+6c99a7aa6eeb797794d6e5a0905168c0296603a77a94ef83d0f1ec68e622416008ccb567c8e371
+84dc90ba11091d9f87e187610260cce3d364311df21d121f89689bb33a7dd35a550d44695e7bde
+d6113d99fad92c0661757957c821aeffd31436b37c2fc5827aae10863bc65d50eb2ed9d4a38450
+b727113bb63d446c53d92337c7dd8d5f67b7baf5153c81c2a44a17352cc1ab1eb368bb8beeb690
+a6bc2af030a04cce7f83e0f61df4b6415f07e8f256c346ff98760a1a1589f6944ca230eafbe84e
+8d5480c24eaa7e595ad952a50beb97224fdfc8caba9289ba92105469e89e8cbe9bc66433666112
+fbba3ce9284fbd621b308c778ba4807e2df24c85ea792ce0cc27280c08f4ee0518cd6838433ea7
+d80e621e304e9e5ea8e0807a3c379be8fde5cab1a078d0ab275c46f8ae5e1dec122d22a357265c
+eaf411fbe8f521915a65a2ce8c93e55506d6ae8ba6d5f21cf62fd3ea1b1a3645b2811a56da5e78
+446ce36990018f6ef03cccd8de783a728da741063cb6c1c3d4d56b7d4f407b1b50a30c807c0b50
+10a1f37804a04619009d0d2021c2d1618f00d42803a0bb05e832c3dc230035ca002836801a6d7f
+52760035ca00e86d013adc7d24291ae57e279555f63a51896ef685973ec610d97abf86f5b86d88
+f4991a62446c4fe0d841946a438c848344180924dc59e4c296ce4cef4f6d88da7e26863698aef9
+e08de47bb67262737758e70fece55460cc21fa7ff546632a07f446bce365dfef8d78c7bb0fe08d
+f8d0deb80b78006fdc053c8037ee021ec01b77010fe08dbb800f7ba3868780f5a5e66ba7ced81c
+3557b52a926b386466b2b5b407f6e7d0f690874e3e7a6c9874cbb2dd7659f65c5d96c738b07d07
+f199c7e17e147a70ec9c11b8245127b44341a3103fbdcb66dd1d8fc5bd0e1e3459736bfeaa159a
+17a396395cdafb43360d48e0f81451378e11e3b1873c970844036f16bb3316b90efb307e0dc892
+4e767929e3fc7aa9e4aba5bee7df1599d5965d50c8a45a6bb13bc5ce914d8f60aac546523086c3
+6feace28b878f9e9af77322f64b52d3afe4c456787b120918f6143c73662b398237f16f8681607
+a117c4ccf56cfef4a29b77aa57dd1fcb44c1748dc2fbc6cde7bf08efb06cbb6bb6eb229755b52c
+4ba97608779e29e19c128f78314521c61e104e29f2fd50c06028f3b0270413f4e9096f8bec7c59
+decbf9374e748f329b300a5d27026d070e85a4bd38423e090314db1111b113738ebdb5d9b4450e
+bb238c6e5f8ff9fcf1ef7375f4f9e33f07b018f3183f5f8ef36e4a837a7cdf7348207ce46306be
+197a2eac5587a39853c6025fcc021a69f53498dd550f54eea79ea67e2b5553e7e6432fb60701ad
+92c21c9a31713927e3aed0ab64335a4dfd85ce1f9e85fa35695ead8c4cfa5d3e30558d96661fba
+09d1b98f5fb64fff050000ffff0300504b030414000600080000002100d5d192f1bc0000003701
+00002c0000007070742f736c6964654c61796f7574732f5f72656c732f736c6964654c61796f75
+74352e786d6c2e72656c738ccfbd0ac2301007f05df01dc2ed26ad8388347511c1c145f4018ee4
+da06db24e4a2e8db9bd18283e37dfdfe5cb37f4da378526217bc865a5620c89b609def35dcaec7
+d5160467f416c7e049c39b18f6ed72d15c68c45c8e78709145513c6b18728e3ba5d80c3421cb10
+c9974917d284b994a95711cd1d7b52ebaadaa8f46d403b33c5c96a48275b83b8be23fd6387ae73
+860ec13c26f2f94784e2d1593a23674a85c5d453d620e5777fb654cb1201aa6dd4ecddf6030000
+ffff0300504b03041400060008000000210068b9a05cc3060000c9200000140000007070742f74
+68656d652f7468656d65312e786d6cec59cd8b1b3714bf17fa3f0c7377fc35e38f25de608fed6c
+92dd64899d941ce5b13ca3b566642479774d0894e4d44ba190965e0abdf5504a030d34f4d23f66
+21a14dff884a1adb33b235dd7c6c42a0eb055bd2fcded34fef3d3dbdd55cbd761a61eb18528648
+dcb2cb574ab605639f8c511cb4ec7bc37ea1615b8c83780c308961cb5e40665fdbfdfcb3ab6087
+87308296908fd90e68d921e7b39d6291f96218b02b640663f16c426804b8e8d2a038a6e044e88d
+70b1522ad58a1140b16dc520126aef4c26c887f6ee4a6d0f8baf983339e0633a904ae136763c2d
+cb1fb6601ea6d631c02d5bcc3026274378ca6d0b03c6c583965d521fbbb87bb5b816c23c473623
+d7579fa5dc52603cad28391a8cd6828ee33ab5f65abf0260be8debd57bb55e6dad4f0180ef8b95
+265c749df58ae72cb11950d234e8eed6bbd5b286cfe8af6ee1dbaefcd3f00a94349d2d7cbfefa5
+36cc8092a6bb85773bcd4e57d7af4049b3b685af97da5da7aee11528c4289e6ea14b6eadeaad56
+bb864c08de33c29baed3af5796f01455cc4457221ff3bc588bc011a17d0150ce051cc5165fcce0
+04f802e7018c461459fb280845e0cd404c98182e554afd52557ccb3f47b59447c10e0419e964c8
+675b43928fc57c8a66bc65df145aed0ce4e58b17678f9f9f3dfefdecc993b3c7bf2ee7de96db03
+7190957bfdd337fffcf0a5f5f76f3fbe7efaad19cfb2f857bf7cf5ea8f3fff4b3dd7687df7ecd5
+f3672fbffffaaf9f9f1ae06d0a4659f810459059b7e18975974462818609e088be9dc43004282b
+d18e03066220650ce81e0f35f4ed05c0c080eb40dd8ef7a9481726e0f5f991467810d2394706e0
+ad30d2800784e00ea1c635dd927365ad308f03f3e4749ec5dd05e0d834b7b7e1e5de7c26e21e99
+547a21d4681e62e17210c018724b3e2353080d620f10d2ec7a807c4a189970eb01b23a00194d32
+44232d9a52a13d1409bf2c4c0485bf35db1cdcb73a049bd477e1b18e147b0360934a8835335e07
+730e22236310e12c721ff0d04472b0a0be6670c685a7038889d51b43c64c3277e842a37b4ba419
+b3db0ff022d29194a3a909b90f08c922bb64ea85209a1939a338cc626fb0a90851601d126e2441
+f41d22fbc20f20ce75f77d0435779fbfb7ef8934640e10f9644e4d5b02127d3f2ef0044093f236
+8db414dba6c8181d9d79a085f63e84189c803184d6bd1b263c9969364f49df0c4556d98326dbdc
+047aacca7e0c19b4547163702c625ac80e604072f81c2c3612cf02c411a0799a6f4ff590e989a3
+2e32c62bf6a75a2a45546e5a33893b2cd2d697abf530045a58c93e33c7eb826afe7b933d26648e
+de4106beb58c48ec6f6c9b21c0da0469c00c81a8324ce9568868ee4f45e476526273a3dc44dfb4
+a91b8a1b454f84e2732ba08ddac7fd38b5cf07ab7a2ebedec94b299b554e1e6eb3b6f1081da34f
+bfb4e982797c08c5697259d95c5636ffc7ca266f3f5fd63397f5cc653df3d1ea99b484511741ab
+eb1ea525cabdfb99208c077c81e13e53c50f137b7fdc1783aaa384d6574db3503497d369b88002
+d5b628e15f201e0e423013d394d50c015baa0e9835234c944f6ad8a85b955ff3e8808c93d17279
+75bb2904004fc745f9b51a17c51a4f466bf5f41a6fad5ef50275ddba222065df864466329d44d5
+40a2be1a3c87845ad985b0681a5834a4fa5c16ea67e915713859405e89bb4ec248849b08e9b1f4
+5322bff2ee857b3acf98fab22b86e53525d78bf1b44622136e3a894c1886e2f0d81cbe605f3753
+976af4a429b669d41b1fc2d732896ce4061ceb3deb44ecb9aa2bd4f860d6b227e21f27d18c6642
+1f93990ae0206ed93e5f1afa5d32cb8c32de052c4c60ea51b2fe0871482d8c2211eb5937e038e5
+56aed4e51a3f5172cdd2a76739f59375329c4ca0cf7346d2ae789628313e7d4fb0ec90b9203d08
+c727d608cfe95d200ce5d6cbd28063c4f8da9a634433c19d5a71235d2db7a2f6d625dda200cf42
+b03c51b2c93c81abf69a4e661d8ae9e6aaf4fe7231a3403ae9bd4fddf385369266ce01224f4d73
+fef870877c86559af7355649eadecc75cd55aecb3b25deff40c8504b27d3a849c6066a7967c705
+160499e9d6a19977465cf469b019b5f28058d595aab7f57a9b8c8e44e47745b53ac79c251764a7
+a2fcf6562f26934ca04657d9e5945b738a5af6c392db76bc8aeb154a0db75770aa4ea9d070dbd5
+42db75abe59e5b2e753b9547c2283c8cca6e32775ffcb38f17cbf7f66a7cebdd7db42ab5aff824
+2a1255071795b07a775fae18dedd5b43f9dcb690b0ccc35aa5dfac363bb542b3daee179c6ea751
+687ab54ea15bf3eadd7ed7731bcdfe23db3a5660a75df59c5aaf51a8953dafe0d44a927ea359a8
+3b954adba9b71b3da7fd68696bb1f2d5efcabc8ad7eebf000000ffff0300504b03040a00000000
+000000210015e9f115040900000409000017000000646f6350726f70732f7468756d626e61696c
+2e6a706567ffd8ffe000104a46494600010101006000600000ffdb004300030202030202030303
+0304030304050805050404050a070706080c0a0c0c0b0a0b0b0d0e12100d0e110e0b0b10161011
+13141515150c0f171816141812141514ffdb00430103040405040509050509140d0b0d14141414
+141414141414141414141414141414141414141414141414141414141414141414141414141414
+14141414141414ffc00011080090010003012200021101031101ffc4001f000001050101010101
+0100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000
+017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282
+090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465
+666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aa
+b2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2
+f3f4f5f6f7f8f9faffc4001f010003010101010101010101000000000000010203040506070809
+0a0bffc400b5110002010204040304070504040001027700010203110405213106124151076171
+1322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a353637
+38393a434445464748494a535455565758595a636465666768696a737475767778797a82838485
+868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8
+c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c030100021103
+11003f00fd53a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a2
+8a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800
+a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a28
+00a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a
+2800a28a2800a28a2800a28a2800a2b83f03fc61d17c6be2af11f86637fb26bba2ddcb04969230
+ccd1ab6d12a7a8e991d54fb104f795ad4a73a52e59ab322338cd5e2ee145145645851451400514
+514005145140051451400514514005145140051451400d7758d19dd82aa8c96638007ad53fedcd
+37fe8216bff7f97fc6b13e2b7fc92ff187fd81af3ff443d7e52d7d2e5393acd23393a9cbcb6e97
+fd51e4e3b1ff0053715cb7bf99faebfdb9a6ff00d042d7feff002ff8d1fdb9a6ff00d042d7feff
+002ff8d7e45515ef7faa6bfe7fff00e4bff04f33fb6dff00cfbfc7fe01faebfdb9a6ff00d042d7
+feff002ff8d1fdb9a6ff00d042d7feff002ff8d7e455147faa6bfe7fff00e4bff043fb6dff00cf
+bfc7fe01faebfdb9a6ff00d042d7feff002ff8d1fdb9a6ff00d042d7feff002ff8d7e455147faa
+6bfe7fff00e4bff043fb6dff00cfbfc7fe01faebfdb9a6ff00d042d7feff002ff8d1fdb9a6ff00
+d042d7feff002ff8d7e455147faa6bfe7fff00e4bff043fb6dff00cfbfc7fe01faebfdb9a6ff00
+d042d7feff002ff8d1fdb9a6ff00d042d7feff002ff8d7e455147faa6bfe7fff00e4bff043fb6d
+ff00cfbfc7fe01faebfdb9a6ff00d042d7feff002ff8d1fdb9a6ff00d042d7feff002ff8d7e455
+147faa6bfe7fff00e4bff043fb6dff00cfbfc7fe01e95f15bc497de1cf8fde28d6745be7b4bdb6
+d627960bab76e41de7f0208e08e84120f15f6bfecf3fb4369df19b46fb2dd79763e29b4406eac8
+1c2cabd3cd8b3d54f71d549c1e304fe6f568787fc41a8f85b59b4d5b49bb92c751b490490dc447
+0cadfd41e841e08241af7f1f93d3c6e1a34ef69c5593f4efe5f91e661b1f3c3d573fb2dea8fd73
+a2bc77f679fda1b4ef8cda37d96ebcbb1f14da20375640e1655e9e6c59eaa7b8eaa4e0f1827d8a
+bf25c461ea616a3a5555a48fb7a75215a0a70774c28a28ae7350a28a2800a28a2800a28a2800a2
+8a2800a28a2800a28a280396f8adff0024bfc61ff606bcff00d10f5f94b5fab5f1514b7c30f178
+0324e8f78001ff005c1ebf2afec73ffcf093fef835fa370ab4a955bf747ca6757e787a321a2a6f
+b1cfff003c24ff00be0d1f639ffe7849ff007c1afbbe65dcf9bb321a2a6fb1cfff003c24ff00be
+0d1f639ffe7849ff007c1a399770b321a2a6fb1cff00f3c24ffbe0d1f639ff00e7849ff7c1a399
+770b321a2a6fb1cfff003c24ff00be0d1f639ffe7849ff007c1a399770b321a2a6fb1cff00f3c2
+4ffbe0d1f639ff00e7849ff7c1a399770b321a2a6fb1cfff003c24ff00be0d1f639ffe7849ff00
+7c1a399770b321a29594ab1041047506b57c2be15d57c6dafd9e8ba2d9c97da8dd3ec8e18ff524
+f40a07249e00144a518c5ca4ec9028b93b2dcd0f86b6be25bcf1c6911f8405c7fc245e7036ad6c
+70cac3a927a05c677678c673c57ea7e86ba8268d62bab3dbcbaa08505d3daa9588cb81b8a03ced
+ce719af38f809f0134bf82ba0607977de21ba41f6dd436fe3e5c79e4203f8b1193d80f55afc8f3
+ccca9e61592a51f763d7abff0081d8fb9cbb092c2d37cef57d3b0514515f347ac1451450014514
+500145145001451450014514500145145001451450014514500145145001451450014514500145
+14500145145007e67fc50f0aeabe36fda23c55a2e8b6725f6a375ac5c2470c7fef9c927a050392
+4f000afb6fe027c04d2fe0ae8181e5df7886e907db750dbf8f971e79080fe2c464f603a3f067c2
+bd13c13e20f106bb6b0f9daceb77725cdcde4a06f0acdb8449fdd51c7d4f27b01d957d26639c4f
+154a186a5a42295fcda5f97fc39e4e17031a339559eb26dfc828a28af9b3d60a28a2800a28a280
+0a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2
+800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28
+a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a
+28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a280
+0a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2800a28a2
+800a28a2800a28a2803fffd9504b030414000600080000002100a364236b8d0100003203000011
+0000007070742f7072657350726f70732e786d6cacd2516fdb201000e0f749fb0f16ef0430368e
+ad38951d1c69d21ea6aafd01c8c6099a310848dba9ea7f1f73d22add34a99af6742074c777709b
+9b273d250fd27965e61a901506899c7b33a8f95083fbbb3d5c83c407310f6232b3acc10fe9c1cd
+f6f3a78dadac935ece418498facd25b1d0ec2b51836308b642c8f747a9855f192be778361aa745
+885b774083138ff1023da1146386b45033b8e4bb8fe49b7154bde4a63fe908381771725a24fea8
+ac7fad663f52edba8f77a46d6c523e85af3e5c56c9c9a91a3c7705db7565d64086e90e66244b61
+5b762d649cd00263829bb478f9954db26a50be176ef8a2c54176830a5c04f18a23d91f3cad7a67
+bc19c3aa37fad227b2e6513a6bd4d22ac197f77a10530d3040db0d5a70ef8d9c9206b3b48145b9
+6e6046d312362de7b06d9b75ce588a7382df8c7214a7292c466ed57fe4d1b460c5df887b9e77fb
+a6e11077bb0e6639ed60b9a60466ac4d69dbc540b33331affaa370e1ce89fe7b9c9b5b39b6c2cb
+e10d9aff0b34bd86926be4392edf8e7e1ff3ed4f000000ffff0300504b03041400060008000000
+2100d8fd8d8fac000000b6000000130000007070742f7461626c655374796c65732e786d6c0ccc
+490e82301840e1bd897768fe7d2d43512414c2202b77ea012a9421e94068a312e3dd65f9f2922f
+cd3f4aa29758ec643403ffe00112ba35dda407068f7b836340d671dd7169b460b00a0b79b6dfa5
+3c714f7973ab1457ebd0a6689b7006a3737342886d47a1b83d9859e8edf56651dc6db90ca45bf8
+7bd3952481e71d89e29306d4899ec137aa8220a2b4c0a7cbe5886948035c7a34c67154d6d5b9a9
+fd2a2c7e40b23f000000ffff0300504b0304140006000800000021006720e9636d010000c60200
+00110000007070742f7669657750726f70732e786d6c8c52c96ec23010bd57ea3f58be978434a4
+3422e152950b874ad0de2dc7492c39b6e5314bf8fa4e365ac485db2c6fdebc5956eb73a3c85138
+904667743e0b29119a9b42ea2aa3dffbcf972525e0992e98325a64b41540d7f9f3d3caa647294e
+5f8e2081869465b4f6dea64100bc160d8399b14263ae34ae611e5d5705856327246e5410856112
+344c6a3ad6bb47ea4d594a2e3e0c3f3442fb81c409c53c8a875a5a98d8ec236cd609409abefa46
+528ec3e90ea87efa113b1fb1de38516c45e9095c70558b240a69f03fb737b64fbdc749d2a7827b
+1e50b2107f2edfa962f0086866f766e3649151bc02d4e6b4392018b0572f898fc023733bce9498
+e2d039f98aa5702678c345440952ccc35e0246dbfb6870adb2a971b2929a9c331a23a6cd68148f
+90b16107aa3a255bf0579b60192e0ff76cdc85126b5066341fc69e207df075194f2dff483af2eb
+e4839cdbbd54b8869d651cbf857094f686d7c14fe4ed640e8cc30be6bf000000ffff0300504b03
+04140006000800000021007749ef2667010000b202000011000801646f6350726f70732f636f72
+652e786d6c20a2040128a000010000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000008c92d14e
+c2301486ef4d7c87a5d76edd980a59b692a8e18248422246e35dd31e46e3d62e6d61f03ebe892f
+6637d800e5c2cbe6ffce97d3bf4dc7dbb2f036a08d5032435110220f24535cc83c43af8b893f42
+9eb154725a280919da814163727d95b22a614ac35cab0ab415603c67922661558656d65609c686
+ada0a426708474e152e9925a77d439ae28fba439e04118dee3122ce5d452dc08fdaa37a28392b3
+5e59ad75d10a38c3504009d21a1c05113eb21674692e0eb4c909590abbabe022da853dbd35a207
+ebba0eeab845ddfe117e9f3dbfb457f5856cba628048ca5962852d80cc550d7aae84b4fe5c7f7f
+19b732b5aeed14f74803330dd42a4da66b99df78d37521e81ee982a6f1821a3b738fb314c01f76
+bfd8bf7933a261239ac7258396e88fe9a1a9bd1fb8e76e98ecfbe892b7f8f1693141641046233f
+8cfde87e110e93284eee861fcd6a67f347617958e0ffc6db241a9d183b0169373eff65e4070000
+ffff0300504b030414000600080000002100e329ddaa0f0200000705000010000801646f635072
+6f70732f6170702e786d6c20a2040128a000010000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+0000a454c16edb300cbd0fd83f18be274eba2d180245459720c8a1590dc44dcf8a45dbc414c990
+b8b4ddf7ec4ff66393e5da4dd6a040579f1ec9e727fa9132bb7cd8abe800d6a1d1b3783c1cc511
+e8dc48d4e52cbecd9683af71e448682994d1308b1fc1c597fce307965a53832504177909ed6671
+45544f93c4e515ec851bfab2f695c2d8bd201fda32314581392c4cfe730f9a928bd16892c00381
+962007752f18b78ad303fdafa83479d39fdb668fb5d7e32c332454867be023963c07ecce58e99a
+5c0bd8555d2bcc057937f81a736b9c2928ba094744a9b9079b1ad4c49263a2f7029c3f3b44cbd0
+1aff660169874ab2e44c95a5c28ad28aba0a871f456ca35082e363963c21f6dd10045a0bd80aa5
+04fd54f5e99398add77385752874906d72a160ee0de185500ebc749f602b10cdb05381d6330f34
+3d404ec6460e7ff9714fe268271c3436cee283b02834c52dad0d0256b523cbb760ef9b5112449b
+bcb25890b07eb62ce919011ebf788cf133ff14081ebc4a6cb516e0b07c8bf8f80de24ba3d08f0c
+09d4fb4f084130d5e353bb332405eea6f00b4067dcff72ec7ee8a1f5be6de7caeb9fb4d7a3b950
+b8b3f85a2dbac6b2a2b38c76dbcf969e6fc020b57f7ef76bfdc2a4ee73fff9c06bd43fdc6d9d99
+8520e896f134c93695b020fd7dee97b54fb09577c2aa863faf842e41769c9785e62a6fdbff1a1f
+4f8623ff845bdbe59a7bd9fd70f85f000000ffff0300504b01022d0014000600080000002100df
+cc18f5ad010000460c00001300000000000000000000000000000000005b436f6e74656e745f54
+797065735d2e786d6c504b01022d001400060008000000210068f874a103010000e20200000b00
+000000000000000000000000e60300005f72656c732f2e72656c73504b01022d00140006000800
+00002100635c23b4c00000003701000020000000000000000000000000001a0700007070742f73
+6c696465732f5f72656c732f736c696465312e786d6c2e72656c73504b01022d00140006000800
+000021001b2e35070c010000d00300001f00000000000000000000000000180800007070742f5f
+72656c732f70726573656e746174696f6e2e786d6c2e72656c73504b01022d0014000600080000
+002100bcd1a735de0200002c0e00001400000000000000000000000000690a00007070742f7072
+6573656e746174696f6e2e786d6c504b01022d0014000600080000002100303a84e5ea0200006c
+0600001500000000000000000000000000790d00007070742f736c696465732f736c696465312e
+786d6c504b01022d0014000600080000002100d5d192f1bc000000370100002c00000000000000
+000000000000961000007070742f736c6964654c61796f7574732f5f72656c732f736c6964654c
+61796f7574362e786d6c2e72656c73504b01022d0014000600080000002100d5d192f1bc000000
+370100002c000000000000000000000000009c1100007070742f736c6964654c61796f7574732f
+5f72656c732f736c6964654c61796f7574372e786d6c2e72656c73504b01022d00140006000800
+00002100d5d192f1bc000000370100002c00000000000000000000000000a21200007070742f73
+6c6964654c61796f7574732f5f72656c732f736c6964654c61796f7574392e786d6c2e72656c73
+504b01022d0014000600080000002100d5d192f1bc000000370100002d00000000000000000000
+000000a81300007070742f736c6964654c61796f7574732f5f72656c732f736c6964654c61796f
+757431302e786d6c2e72656c73504b01022d0014000600080000002100d5d192f1bc0000003701
+00002c00000000000000000000000000af1400007070742f736c6964654c61796f7574732f5f72
+656c732f736c6964654c61796f7574382e786d6c2e72656c73504b01022d001400060008000000
+2100d5d192f1bc000000370100002d00000000000000000000000000b51500007070742f736c69
+64654c61796f7574732f5f72656c732f736c6964654c61796f757431312e786d6c2e72656c7350
+4b01022d0014000600080000002100d5d192f1bc000000370100002c0000000000000000000000
+0000bc1600007070742f736c6964654c61796f7574732f5f72656c732f736c6964654c61796f75
+74312e786d6c2e72656c73504b01022d0014000600080000002100d5d192f1bc00000037010000
+2c00000000000000000000000000c21700007070742f736c6964654c61796f7574732f5f72656c
+732f736c6964654c61796f7574322e786d6c2e72656c73504b01022d0014000600080000002100
+d5d192f1bc000000370100002c00000000000000000000000000c81800007070742f736c696465
+4c61796f7574732f5f72656c732f736c6964654c61796f7574332e786d6c2e72656c73504b0102
+2d0014000600080000002100d5d192f1bc000000370100002c00000000000000000000000000ce
+1900007070742f736c6964654c61796f7574732f5f72656c732f736c6964654c61796f7574342e
+786d6c2e72656c73504b01022d001400060008000000210069a25f2115010000c70700002c0000
+0000000000000000000000d41a00007070742f736c6964654d6173746572732f5f72656c732f73
+6c6964654d6173746572312e786d6c2e72656c73504b01022d0014000600080000002100e40b4c
+2ac6040000891000002200000000000000000000000000331c00007070742f736c6964654c6179
+6f7574732f736c6964654c61796f757431312e786d6c504b01022d0014000600080000002100ee
+0bf3bf90040000a70f00002200000000000000000000000000392100007070742f736c6964654c
+61796f7574732f736c6964654c61796f757431302e786d6c504b01022d00140006000800000021
+005a9d379569050000671500002100000000000000000000000000092600007070742f736c6964
+654c61796f7574732f736c6964654c61796f7574332e786d6c504b01022d001400060008000000
+21008f55c3fd730400006b0f00002100000000000000000000000000b12b00007070742f736c69
+64654c61796f7574732f736c6964654c61796f7574322e786d6c504b01022d0014000600080000
+0021007555dfd224050000701200002100000000000000000000000000633000007070742f736c
+6964654c61796f7574732f736c6964654c61796f7574312e786d6c504b01022d00140006000800
+00002100fd00fcd1320800004e3600002100000000000000000000000000c63500007070742f73
+6c6964654d6173746572732f736c6964654d6173746572312e786d6c504b01022d001400060008
+00000021009119fff8d4040000951300002100000000000000000000000000373e00007070742f
+736c6964654c61796f7574732f736c6964654c61796f7574342e786d6c504b01022d0014000600
+080000002100d60634cc2e060000371f000021000000000000000000000000004a430000707074
+2f736c6964654c61796f7574732f736c6964654c61796f7574352e786d6c504b01022d00140006
+00080000002100ccacc02fe8030000060c00002100000000000000000000000000b74900007070
+742f736c6964654c61796f7574732f736c6964654c61796f7574362e786d6c504b01022d001400
+06000800000021005632cb5c8e030000fa0900002100000000000000000000000000de4d000070
+70742f736c6964654c61796f7574732f736c6964654c61796f7574372e786d6c504b01022d0014
+0006000800000021004ba90907dd050000651700002100000000000000000000000000ab510000
+7070742f736c6964654c61796f7574732f736c6964654c61796f7574382e786d6c504b01022d00
+140006000800000021004a0963b7a1050000201700002100000000000000000000000000c75700
+007070742f736c6964654c61796f7574732f736c6964654c61796f7574392e786d6c504b01022d
+0014000600080000002100d5d192f1bc000000370100002c00000000000000000000000000a75d
+00007070742f736c6964654c61796f7574732f5f72656c732f736c6964654c61796f7574352e78
+6d6c2e72656c73504b01022d001400060008000000210068b9a05cc3060000c920000014000000
+00000000000000000000ad5e00007070742f7468656d652f7468656d65312e786d6c504b01022d
+000a00000000000000210015e9f11504090000040900001700000000000000000000000000a265
+0000646f6350726f70732f7468756d626e61696c2e6a706567504b01022d001400060008000000
+2100a364236b8d010000320300001100000000000000000000000000db6e00007070742f707265
+7350726f70732e786d6c504b01022d0014000600080000002100d8fd8d8fac000000b600000013
+00000000000000000000000000977000007070742f7461626c655374796c65732e786d6c504b01
+022d00140006000800000021006720e9636d010000c60200001100000000000000000000000000
+747100007070742f7669657750726f70732e786d6c504b01022d00140006000800000021007749
+ef2667010000b2020000110000000000000000000000000010730000646f6350726f70732f636f
+72652e786d6c504b01022d0014000600080000002100e329ddaa0f020000070500001000000000
+000000000000000000ae750000646f6350726f70732f6170702e786d6c504b0506000000002500
+25004d0b0000f37800000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000002004f006c00650050007200650073003000300030000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000001800020103
+00000005000000ffffffff00000000000000000000000000000000000000000000000000000000
+000000000000000003000000fc010000000000005200690063006800450064006900740046006c
+006100670073000000000000000000000000000000000000000000000000000000000000000000
+0000000000001c000200ffffffffffffffffffffffff0000000000000000000000000000000000
+000000000000000000000000000000000000000b0000000c000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000ffffffffffffff
+ffffffffff00000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000fa020000040000002f528f00040000002d010400070000
+00fc020100000000000000040000002d010500120000002403070065026a03e4086a03e408af02
+5a0a2504e4089b05e408e0046502e004040000002d010200040000002d01030004000000f00104
+00040000002701ffff040000002c010000070000001604cf08a80f00000000030000001e000400
+00002c010000040000002701ffff0300000000000000000000000000000000000000000000004e
+414e49000000000000000001000008000000000100000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000
+01050000
+05000000
+0d000000
+4d45544146494c455049435400
+0a450000
+28d9ffff
+c2010000
+08000a45d8260000
+010009000003dd00000006001200000000000400000003010800050000000b0200000000050000
+000c02cf08a80f030000001e0007000000fc020000ffffff000000040000002d01000008000000
+fa02050000000000ffffff00040000002d0101000e00000024030500ffffffffffffcf08a80fcf
+08a80fffffffffffff08000000fa0200000000000000000000040000002d01020007000000fc02
+0000ffffff000000040000002d01030004000000f001000007000000fc0200004472c400000004
+0000002d0100000400000006010100040000002d010100120000002403070065026a03e4086a03
+e408af025a0a2504e4089b05e408e0046502e004040000002d0102000400000006010100040000
+002d01030008000000fa020000040000002f528f00040000002d01040007000000fc0201000000
+00000000040000002d010500120000002403070065026a03e4086a03e408af025a0a2504e4089b
+05e408e0046502e004040000002d010200040000002d01030004000000f0010400040000002701
+ffff040000002c010000070000001604cf08a80f00000000030000001e00040000002c01000004
+0000002701ffff030000000000
+}{\result{\pict\wmetafile8\picw10020\pich5638\picwgoal10020\pichgoal5638
+010009000003dd00000006001200000000000400000003010800050000000b0200000000050000
+000c02cf08a80f030000001e0007000000fc020000ffffff000000040000002d01000008000000
+fa02050000000000ffffff00040000002d0101000e00000024030500ffffffffffffcf08a80fcf
+08a80fffffffffffff08000000fa0200000000000000000000040000002d01020007000000fc02
+0000ffffff000000040000002d01030004000000f001000007000000fc0200004472c400000004
+0000002d0100000400000006010100040000002d010100120000002403070065026a03e4086a03
+e408af025a0a2504e4089b05e408e0046502e004040000002d0102000400000006010100040000
+002d01030008000000fa020000040000002f528f00040000002d01040007000000fc0201000000
+00000000040000002d010500120000002403070065026a03e4086a03e408af025a0a2504e4089b
+05e408e0046502e004040000002d010200040000002d01030004000000f0010400040000002701
+ffff040000002c010000070000001604cf08a80f00000000030000001e00040000002c01000004
+0000002701ffff030000000000
+}}} \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/ole2.png b/sw/qa/extras/htmlexport/data/ole2.png
new file mode 100644
index 0000000000..fdad35484e
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/ole2.png
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/paint-ole-bitmap-format.odt b/sw/qa/extras/htmlexport/data/paint-ole-bitmap-format.odt
new file mode 100644
index 0000000000..d83b894597
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/paint-ole-bitmap-format.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/paint-ole.ole b/sw/qa/extras/htmlexport/data/paint-ole.ole
new file mode 100644
index 0000000000..e8e78490ed
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/paint-ole.ole
@@ -0,0 +1,199 @@
+{\object\objemb{\*\objclass PBrush}\objw13852\objh7822{\*\objdata
+01050000020000000700000050427275736800000000000000000000440000
+424de64300000000000036000000280000004c0000004c0000000100180000000000b043000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9894f6241ced241ced
+7d79f5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4039ef241ced241ced241cedf8f8feffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1bffa322aee241ced241ced625cf2f8f8feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa6a2f7241ced241ced241ced625cf2f8f8feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff918df6241ced241ced241ced625cf2f8f8feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff918df6241ced241ced241ced625cf2f8f8feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff918df6241ced241ced241ced625cf2
+f8f8feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff918df6241ced241ced241ced625cf2f8f8feffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff918df6241ced241ced241ced706af4ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff918df6241ced241ced241ced7d79f5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff3931ef241ced241ced241ced625cf2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9894f6241ced241ced7d79f5ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffc1bffa322aee241ced241ced241cedbab8f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2b23ee241ced241ced2b23eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1bffa4039ef241ced241ced4d47f1ffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8fe241ced241ced241cedadaaf8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeafd241ced241ced241cedffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffff8f8fe7772f4241ced241ced241ced2b23eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3931ef241ced241cedbab8f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8480f5241ced
+241ced241ced241ced9894f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8480f5241ced241ced4d47f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9894f6241ced241ced241ced4039efa6a2f7ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffeaeafd241ced241ced241cedadaaf8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8fe2b23ee241ced241ced2b23eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3931ef
+241ced241ced241ced625cf2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8480f5241ced241ced2b23eeadaaf8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbab8f9322aee241ced241ced241cedbab8f9ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff2b23ee241ced241ced9894f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f1fe706af4241ced241ced4d47f1ffffffffffffffffffffffffffffffffffffffffffffffffbab8f9241ced241ced
+241cedffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeafd2b23ee241ced241cedcfcdfbffffffffffffffffffffffffffffffffffff7d79f5241ced241ced241ced2b23eeffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7d79f5241ced241ced8b87f6ffffffffffffffffffffffffffffffd6d4fb241ced241ced241ced2b23ee9894f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffc8c6fa241ced241ced4039effffffffffffffffffffffffff8f8fe5b55f2241ced241ced5b55f2eaeafdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3931ef241ced241ced
+bab8f9fffffffffffff8f8fe625cf2241ced241ced241cedd6d4fbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8480f5241ced241ced4d47f1f8f8fef8f8fe625cf2241ced241ced241ced918df6
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeafd2b23ee241ced241ced625cf2746ff3241ced241ced241ced918df6ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa6a2f7241ced241ced241ced241ced241ced241ced918df6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff918df6241ced241ced241ced241cec6963f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffff8f8fe413af0241ced241ced241cedbab7f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8fe625cf2241ced241cee241ced241ced544ef1f8f8fe
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8fe625cf2241ced241ced241cec281fee241ced241ced625cf2f8f8feffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbab8f94d47f1241ced241ced241ced918df69f9bf7241ced241ced241ced625cf2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffff8f8fe6963f3241ced241ced241ced241ced918df6ffffffffffff918df6241ced241ced241ced9894f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8fe625cf2241ced
+241ced241ced2b23ee9894f6ffffffffffffffffffffffff8b87f6241ced241ced2b23eedddbfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7772f4241ced241ced241ced7d79f5eaeafdffffffffffffffffffffffffffffff
+f8f8fe4d47f1241ced241ced544ef1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6d4fb241ced241ced241ced918df6ffffffffffffffffffffffffffffffffffffffffffffffffd6d4fb2b23ee241ced241ced9894f6ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeafd544ef1241ced241ced6963f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9894f6241ced241ced2b23eedddbfcffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffadaaf8322aee241ced241ced241cedd6d4fbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff544ef1241ced241ced544ef1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8fe6963f3241ced241ced241ced241ced
+9894f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4e3fd2b23ee241ced241cedbab8f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8fe625cf2241ced241ced241ced4640f0cfcdfbffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff8480f5241ced241ced4d47f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8fe625cf2241ced241ced241ced8480f5f8f8feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeafd2b23ee
+241ced241ced9894f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffd6d4fb8480f54039ef241ced241ced241ced918df6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9894f6241ced241ced2b23eedddbfcffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8fe6963f3
+241ced241ced241ced241ced241ced918df6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff544ef1241ced241ced544ef1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8fe625cf2241ced241ced241ced241ced3931ef9f9bf7ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4e3fd2b23ee241ced241cedbab8f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8fe625cf2241ced241ced241ced7772f4c8c6faffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8480f5241ced241ced4d47f1f8f8feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8c6fa544ef1241ced241ced241ced918df6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffeaeafd2b23ee241ced241ced706af4ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffc8c6fa5b55f2241ced241ced241ced241ced918df6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa6a2f7241ced241ced2b23ee
+f8f8feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeafd625cf2241ced241ced241ced241ced2b23ee
+9894f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffadaaf85b55f2adaaf8ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffadaaf8322aee241ced241ced241ced2b23ee8480f5eaeafdffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8fe6963f3241ced241ced241ced241ced8480f5eaeafdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff8480f5241ced241ced241ced4640f0cfcdfbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+4039ef241ced241ced8480f5f8f8feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1bffa5b55f2a6a2f7ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000000001050000050000000d0000004d45544146494c45504943540049060000b7f9ffff2c1b00000800490649060000
+010009000003920d00000000690d000000000400000003010800050000000b0200000000050000000c024d004d00030000001e0004000000070104000400000007010400690d0000410b2000cc004c004c00000000004c004c0000000000280000004c0000004c0000000100080000000000000000000000000000000000
+000000000000000000000000ffffff00c1bffa005b55f200a6a2f7004039ef00241ced008480f500f8f8fe004640f000cfcdfb006963f300eaeafd00adaaf800322aee002b23ee00625cf2009894f600c8c6fa00918df600544ef100706af4007772f4004d47f1003931ef009f9bf700e4e3fd00bab8f900d6d4fb00dddb
+fc007d79f5008b87f600241cec00281fee00241cee00413af000bab7f900746ff300f1f1fe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101011106061e0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010506060608
+0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101020e0606100801010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010406060610080101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101130606061008010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010113060606100801010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+011306060610080101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101130606061008010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+01010101010101010101010101010101010101010101010101010101011306060615010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101130606061e010101010101010101010101010101
+0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101011806060610010101010101010101010101010101010101011106061e0101010101010101010101010101010101010101010101010101010101010101010101010101010101
+01010101010101020e0606061b0101010101010101010101010101010101010f06060f0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010102050606170101010101010101010101010101010101080606060d010101010101010101010101010101
+01010101010101010101010101010101010101010101010101010101010101010101010c06060601010101010101010101010101010108160606060f010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101011806061b01010101010101010101
+010101010706060606110101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010107060617010101010101010101010101011106060605040101010101010101010101010101010101010101010101010101010101010101010101010101010101
+0101010101010101010101010c0606060d0101010101010101010101080f06060f01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101011806060610010101010101010101010706060f0d0101010101010101010101010101010101
+0101010101010101010101010101010101010101010101010101010101010101010101010101011b0e0606061b0101010101010101010f0606110101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010126150606170101010101
+0101011b0606060101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010c0f06060a0101010101011e0606060f01010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+0101010101010101010101010101010101011e06061f01010101011c0606060f1101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101120606050101010108030606030c010101010101010101010101010101010101
+0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101011806061b010108100606061c010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010706061708
+08100606061301010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010c0f0606102506060613010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+01010101010101010101010101010101010101010101040606060606061301010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010113060606200b010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010823060606240101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010810
+062206061408010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010810060620210606100801010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101011b17060606131906060610010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101080b06060606130101130606061101010101010101010101010101010101
+01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010108100606060f11010101011f06060f1d010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101160606061e
+0c0101010101081706061401010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101011c0606061301010101010101011c0f0606110101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010c1406060b010101010101010101011106060f1d010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010d0e0606061c0101010101010101010101140606140101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101080b06060606110101010101010101010101011a0f06061b0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010810060606090a0101
+010101010101010101010101070606170101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101081006060607080101010101010101010101010101010c0f060611010101010101010101010101010101010101010101010101010101010101010101
+01010101010101010101010101011c0705060606130101010101010101010101010101010101011106060f1d0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101080b060606060613010101010101010101010101010101010101010114060614010101010101
+0101010101010101010101010101010101010101010101010101010101010101010101010108100606060618190101010101010101010101010101010101010101011a0f06061b01010101010101010101010101010101010101010101010101010101010101010101010101010101010810060606161201010101010101
+0101010101010101010101010101010101070606170801010101010101010101010101010101010101010101010101010101010101010101010101010112140606061301010101010101010101010101010101010101010101010101010c0f06061501010101010101010101010101010101010101010101010101010101
+01010101010101010112030606060613010101010101010101010101010101010101010101010101010101010406060f08010101010101010101010101010101010101010101010101010101010101010101010c10060606060f110101010101010101010101010101010101010101010101010101010101010d030d0101
+01010101010101010101010101010101010101010101010101010101010101010d0e0606060f070c010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101080b06060606070c010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010107060606090a01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101050606070801010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010203040101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
+01010101040000002701ffff030000000000
+}{\result{\pict{\*\picprop}\wmetafile8\picw13852\pich7822\picwgoal13852\pichgoal7822
+}}}
diff --git a/sw/qa/extras/htmlexport/data/paint-ole.png b/sw/qa/extras/htmlexport/data/paint-ole.png
new file mode 100644
index 0000000000..8388f7382f
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/paint-ole.png
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/paint-ole.xhtml b/sw/qa/extras/htmlexport/data/paint-ole.xhtml
new file mode 100644
index 0000000000..efe3326ad9
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/paint-ole.xhtml
@@ -0,0 +1,9 @@
+<reqif-xhtml:div><reqif-xhtml:p><reqif-xhtml:br/>
+
+</reqif-xhtml:p>
+<reqif-xhtml:p><reqif-xhtml:object data="paint-ole.ole" type="text/rtf">
+<reqif-xhtml:object data="paint-ole.png" type="image/png" width="533" height="378"/>
+</reqif-xhtml:object><reqif-xhtml:br/>
+
+</reqif-xhtml:p>
+</reqif-xhtml:div>
diff --git a/sw/qa/extras/htmlexport/data/pdf-ole.odt b/sw/qa/extras/htmlexport/data/pdf-ole.odt
new file mode 100644
index 0000000000..184449a4f8
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/pdf-ole.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/reqif-aschar-objsize.odt b/sw/qa/extras/htmlexport/data/reqif-aschar-objsize.odt
new file mode 100644
index 0000000000..6028b54a41
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-aschar-objsize.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/reqif-chinese.odt b/sw/qa/extras/htmlexport/data/reqif-chinese.odt
new file mode 100644
index 0000000000..b99c57caee
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-chinese.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/reqif-jpg-img.xhtml b/sw/qa/extras/htmlexport/data/reqif-jpg-img.xhtml
new file mode 100644
index 0000000000..da7276192a
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-jpg-img.xhtml
@@ -0,0 +1,4 @@
+<reqif-xhtml:div><reqif-xhtml:br/>
+ <reqif-xhtml:img data="reqif-ole-img.jpg" type="image/jpeg">OLE Object</reqif-xhtml:img>
+</reqif-xhtml:div>
+
diff --git a/sw/qa/extras/htmlexport/data/reqif-list.xhtml b/sw/qa/extras/htmlexport/data/reqif-list.xhtml
new file mode 100644
index 0000000000..5433ee10a6
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-list.xhtml
@@ -0,0 +1,11 @@
+<reqif-xhtml:div>Heading<reqif-xhtml:br/>
+ <reqif-xhtml:ul>
+ <reqif-xhtml:li>
+ <reqif-xhtml:strong>First</reqif-xhtml:strong></reqif-xhtml:li>
+ <reqif-xhtml:li>
+ <reqif-xhtml:strong>Second</reqif-xhtml:strong></reqif-xhtml:li>
+ <reqif-xhtml:li>
+ <reqif-xhtml:strong>Third</reqif-xhtml:strong>
+ </reqif-xhtml:li>
+ </reqif-xhtml:ul>
+</reqif-xhtml:div>
diff --git a/sw/qa/extras/htmlexport/data/reqif-no-lang.odt b/sw/qa/extras/htmlexport/data/reqif-no-lang.odt
new file mode 100644
index 0000000000..c831921a42
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-no-lang.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/reqif-objdata-presentationdatasize.odt b/sw/qa/extras/htmlexport/data/reqif-objdata-presentationdatasize.odt
new file mode 100644
index 0000000000..231a7c572a
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-objdata-presentationdatasize.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/reqif-ole-data.ole b/sw/qa/extras/htmlexport/data/reqif-ole-data.ole
new file mode 100644
index 0000000000..d3dc23d793
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-ole-data.ole
@@ -0,0 +1 @@
+{\pict}
diff --git a/sw/qa/extras/htmlexport/data/reqif-ole-data.xhtml b/sw/qa/extras/htmlexport/data/reqif-ole-data.xhtml
new file mode 100644
index 0000000000..5f9c894000
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-ole-data.xhtml
@@ -0,0 +1,3 @@
+<reqif-xhtml:div>
+ <reqif-xhtml:object data="ole2.ole" type="text/rtf"/>
+</reqif-xhtml:div>
diff --git a/sw/qa/extras/htmlexport/data/reqif-ole-img.jpg b/sw/qa/extras/htmlexport/data/reqif-ole-img.jpg
new file mode 100644
index 0000000000..ca9183e9d3
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-ole-img.jpg
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/reqif-ole-img.png b/sw/qa/extras/htmlexport/data/reqif-ole-img.png
new file mode 100644
index 0000000000..fdad35484e
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-ole-img.png
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/reqif-ole-img.xhtml b/sw/qa/extras/htmlexport/data/reqif-ole-img.xhtml
new file mode 100644
index 0000000000..df3f4a048e
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-ole-img.xhtml
@@ -0,0 +1,6 @@
+<reqif-xhtml:div><reqif-xhtml:br/>
+ <reqif-xhtml:object data="ole2.ole" type="text/rtf">
+ <reqif-xhtml:object data="reqif-ole-img.png?test=true" type="image/png">OLE Object</reqif-xhtml:object>
+ </reqif-xhtml:object>
+</reqif-xhtml:div>
+
diff --git a/sw/qa/extras/htmlexport/data/reqif-ole-nodata.odt b/sw/qa/extras/htmlexport/data/reqif-ole-nodata.odt
new file mode 100644
index 0000000000..a4d3243a8b
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-ole-nodata.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/reqif-ole-odg.ole b/sw/qa/extras/htmlexport/data/reqif-ole-odg.ole
new file mode 100644
index 0000000000..de674fe3c6
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-ole-odg.ole
@@ -0,0 +1,146 @@
+{\object\objemb{\*\objclass }{\*\objdata
+000000000200000000000000000000000000000000240000d0cf11e0a1b11ae1000000000000000000000000000000003b000300feff09000600000000000000
+00000000010000000f00000000000000001000000200000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffdfffffffffffffffefffffffeffffff05000000060000000700000008000000090000000a000000
+0b0000000c0000000d0000000e000000feffffff10000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff52006f006f007400200045006e007400720079000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000feffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000feffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000feffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000feffffff000000000000000001000000fefffffffefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff0100feff030a0000ffffffff71b78b44e2cfc447bcdf1fbf378e202c1b0000004c696272654f6666
+6963652e44726177446f63756d656e742e310010000000456d626564646564204f626a6563740000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000001000002000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000143700000000000010270000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000504b0304140000080000a26dbe4c9f032ec42b0000002b000000080000006d696d65747970656170
+706c69636174696f6e2f766e642e6f617369732e6f70656e646f63756d656e742e6772617068696373504b0304140008080800a26dbe4c000000000000000000
+0000000c00000073657474696e67732e786d6cb5585b6fda30147edfaf405127b50f107ad13a22a02a6d59abb18d15e89e0fc9815875ecc8764af9f73b49a0a2
+102a1af013c2f6f9ce77ee769a57af11afbca0d24c8a96735aab3b1514be0c9898b69cd1b05bfdee5cb5bf34e564c27cf402e927110a53d5680c1dd1151217da
+cbb75b4ea284274133ed0988507bc6f7648c6229e6ad9ef63265f9ca2b67e2b9e584c6c49eebce66b3daecbc26d5d43d6d341a6eb6bb3c1a2bd404052623bc9b
+c2559955b5be141336dd15253fbd2a2fa57c239d0ae48665c4cfeaf50b37ffbf3cad23c677d5959eadfa328a89f398bff3150816ed0a939eddb03a67f531f7c6
+1bf745b05652e4cc692ff3619906ede6c239f94f95198cd21ca92c96538e2d87547a2f0c676fd9e314c9bd9779623a75c0b54218cad8596e9a794c9b4c18a75d
+6fba9b209f02eee1c4d841fec7021316419f5ed41b8dbde1ef914dc342ea54365be00b16d378ec1ec17c2151595e7d2694d771cce7238dea160cac911e4bc911
+84d3362ac1727ee93013413c04f2cde8b1b786af8d22964efbe878ac400463d098287ee2ea1014ba31703203bf9e778e8e13224855179e2c48b8da9000a8a0a6
+e5b81cb31b5202be417543054dad282da421d15ae7184a553eeb6e2497caaaf57e3962b7a043abbc8292bc70020937446d608a3bcbe9d965c960dc45630cba52
+18bd2dcf27c075c944ffa12060d4e3ad3a755a8edb3d18df6eb4c372c41ef44f54e25a3310fd44f826c9da9785e83ce83e99693a523e9341d61574c07f3e7c2f
+7dafa3ab2893ad29a169b0de090fe8a62e337d985a5470cf820045aa636badefeda214fd372dd8b362c838daf5d39059e1df6302ef4460b5e594a52621784408
+a4e0730b96ff42d089c29160ebb5b9b8485c96c3cd922da101a6ba52d1eba168325e9485563055108783248a6c35e02cdbfe26c0995977fb3eb7fa0c16d58308
+307d67d1fcedc15c261bbe5f641c97b32a5df5244f5233f7525950f90b2deece187d88299e4a460334c9fa65e7605e4755084f55f7eda2c304a8f92e9407f082
+4ff973f38fb8e152dbe81b039f8aff969ebd11f1325215defff680a60a427560e0511cd0ac4ca338c428e61fcccded1367ebf3cfdd78d2bbdb3efab4ff03504b
+07089f6ee54e2b03000036120000504b0304140008080800a26dbe4c0000000000000000000000000b000000636f6e74656e742e786d6cbd58518fa336107eef
+af409cd437e290dcdd6ee826275555a54abba753774faaeecd6b0cb8c518d92624fdf53736e09864c9a25eb52f41d8df371e7f339ec1b9fb74e065b0a7523151
+6dc378b10c035a1191b22adf865f9f7e8f6ec34fbb9fee4496314293549086d34a4744541a9e01b02b9574b3dbb0915522b0622aa930a72ad1241135ad0656e2
+a313bb5637a2f4b19c4db7609fade941cf251bec888b9fe7af6cc13e3b95b89d4b365810d5a767622ef9a0ca2813a03aafb166675e1c4a56fdb30d0badeb04a1
+b66d17ed7a21648ee2cd6683ecac7398385cddc8d2a252826849cd620ac58b180d584e359eeb9fc1fa2e550d7fa672b63458e38ba8d6922a80c0764d62ce33e4
+7346f9b5cf6767d73e9f90991458cece330b1ea7ca3a9d9f2aebd4e772ac8b89f8dea20798b43f0ff7a7bc927cee5a063b928a4856cfde6687f6f94208e7aa21
+7487ddbabb5a2edfa3eedd43b757e1ad649a4a0f4eaec2092e89535cf09744035c8c0011d1bd497977888c106a82b042ddb403ab74d2f45f0ff78fa4a01c9fc0
+ec7570c42aa5717552467156ce8e0260279216576c762a18ecc5d19126192615ff8024ad85d42e40d9fc2600abac9c4685e6e5740933b303349769fa2214dc59
+232867504ca23da3edbb70d49dae27e6e62c316da97f8d62417e2fb84a8897c8605c3981543d352e99bbde9a89a64abb387402d2434d253353b8b4b46464c18f
+5629fe83c9be1f7b16464d8ad172a85c6e4b2f9a1122e20a12190eaca8138f3dee79921fe699338754a4d9b9c5b38245945aeb97f2e1e94f64e622d3f2a1a9f5
+2b799f3aab70377cd774754c213790c1f74d946142a3949252edeebafee48683eeddf8bd0def19343b2b6ff0882ba812d04406281ccde336fc19d742fd7286eb
+06c36064dae0a39c562004943a2938ae46889a6902cd608f25b3d987e6bb0626b359be19e05b38f75968715d3187786bad60c9f87f8ca33a2a4df90f39d71096
+e257f2eb8479139f1e692e68f0f58f498706c09b78f3840b61baee852f6ee247574753c5a11fc78d16a68392c8da7155c3fe8e7c4debd82dd67bd9df0fa21ae7
+de562fa9b9bca0e612d70523c3708da5b9a2d997a823996f8b14cb341cecf694a886c24aa5665405c6017b3f023a8e0a21d9bfc254e208972c8782f977a334cb
+8ee119706fe8e404e30cfa33ed5146912897a28d0acaf202ea74864b05b3994838abdc28dc3bdedf10eec65b969a4fde78f1f1c306868df69e1ed3e27cb9d006
+c4c076b36eeb6ec4df3cac6b76346c8250d3732ed7459391ee279e457a742f7d487777560b13d84e95ce57f31ef73af9b1b2b9614739dc8aa8b419d1cffd4633
+dc943aec4d120889e0912a704d2f0dd94c71c11ae5c39761a6c447734f8387687477767aed578bd86a6fc74e715a6f6e864168e36b1f7434a49b9b5b78dfddd9
+8b768d7a476955988fdb144e9c80bba23c5a82f94afb55809965b00c56f1c765ff3b787dacc1554909246fee52ca99aaedade82130e4fb9e3e32139c9ecbe05b
+f0d986f342b761cca87c0ab00b1d1a05164dfc0fb2fb0e504b0708a84c77df6004000048110000504b0304140008080800a26dbe4c0000000000000000000000
+000a0000007374796c65732e786d6ced5c5f73db36127fbf4fa151e7ee8da6484bb6a58bddb9de4d6f3ad3a49dfc79e853072241090d497040d0b2f325eef1be
+df7d92dbc51f1294489ab65527519bccd8117601ecfe76b1582ca0bcfaf62e4b27b754948ce7d7d3e06c369dd03ce231cb37d7d30fefbff7aea6dfdefce5154f
+1216d155cca32aa3b9f44a799fd272029df372a589d7d34ae42b4e4a56ae7292d17225a3152f686e3bad5cee959a4ab7a8c1c67657cc6e6f49efe4d8cec8dbea
+4bd6e36756cc6eef5890ddd8cec80b98badd133eb6f35d997a09f7229e1544b23d29ee52967fbc9e6ea52c56bebfdbedce76e7675c6cfc60b95cfa8a5a0b1cd5
+7c452552c515473e4d294e56fac159e05bde8c4a32563ee47545caab6c4dc56868882407562d042d8105d445bf1c3790dba7e55fb79bd1de75bbe98139da1231
+dacf1473db55cee3f1ae721ebb7d3322b73df6bdf25f0351fd78fd63e357221b3b17f2b6a08a042b46aba9b9ddfe9cf35a54eca017bb12379ccde6befeec70ef
+06d97782492a1cf668903d22695423ceb32ed0802ff081c3a3b7e8f2b5de194b476b0dbc3d4e4272361a7ae43d705581e0f76ab8f0052db8903520c9f8a00bb3
+8475c8d8ca2ced0f1948b5ac1b11c79dac20ceb90fe10316af77cbe8ee9b696b37187684e59e23a8d0fa5017c5e4c6dec10ec1cc479e7af9826b341b85d8d45b
+59c2ab3cd676d000d2bb820a862492aa6eabd608aeb552fe8421cdfee78cd0da14184d6da4a855ea1c86732f2b3d96c302e1c5cae9dd8a5a65792ebbccf7fead
+8f340f774488f9661e271108a73776d74f38ecf80989a817d3282d6f5ee9685d374ff46714f27afa2383d0af949fbc23392c3008a9961516cefdf5f46fa4e0e5
+dff7f874e374d21a1af9bd0dcd416b58f88267246f71144c46101a6f8960ca37fcf1a2c190c928d990f125847bc3251f46ace67869ac60cae088762cef4b49b3
+670957452c260ff857c3f32232bda31b4e271f7ee815c832bc8834efc9163ca043969af0dcd9fdbee060daf509e1e6150661d84548cc206e4dd4272de2f72c4d
+69fc6b38fbf5bbb482b8ae48312b8b94dc7b2ecbc4a19ba30224b59488ba0d922dd890530e29e73797e132891243827db0269c2f16e1c5b2d50783675e3209b8
+04b3d95f9d4edd14926f70f6f3d9cc34acb98831d1050e7f94aaff1694e643baba0c2394bd5c47178b0e6583f0f2220c3fb3b26f693ca46a437e58d124b9882f
+e20e45a3651804f4332bfa0b4d53be1bd2b5c53146dd982e961deaaee79757b3f9efae6e46c4472a5c65ff2104ca8ff104b3bdeff81d7498cc26e16c723ed3ed
+90b6bc0ea02df5026cdc86b34f4d988a6942aad4140e6c68313109c02db62c9a5a5ef3d92b20b1a142325aaaf14b29f847daace7f9c58258281280f92004247c
+b583a13c5ee85364ce3dfcdc08551041d464ada91409f3228f54929705c1da068b29d7ac242db675002daa3c9295dafed4d8103d5956609aaae968636f2d2881
+133ac8cf22d98aab2c8f2926eb585251ac389b2abd24242d698d08a4be801c2f4a0cbcfdb2d7ec28fc814a5549bd1dccc8779e9adcc02545455b42f5254b00a7
+a297ec13d0c37921555b0a0e55910d3461e0828608d25f29c0ae1fde1d8cebc14985e4adddb261c0812d831ede806866b0b44f5b4b315359c23fdf1c4e8807b5
+94de75ee7c6ac29aa173ca9aba65fb93d6a41fde4c1bbbb41cdd1ac4f57a0d2fac5d38238878faf8b560d63e2e061887a72c9ebaeb63c762ac17cca26cfae0b2
+d1ebdcd381c4763c0bb1eb213da278d6b0aed962c068d3df5d05b08eceb8686b0dfa97b1a2a04b135847de960bf689e311085622db80d57fab4ac9927be57b05
+89b174e9c15a4151827081c238843597122b035db494265229b04f106cb37528da005b12abea058be366c7568d1ea4402595de5d1b8d36f1be936875bf9ae15f
+f00255b14c59d98e9c7b3ee4b2a5f496a69ad95b57b0f9c88926623b6c0453fd51933c2c545d4ffff7dfffd40ee70ce2f89cea93b1dc4bc91a28b5ad2f4001bf
+2fecd880617dfb1d58f0dd7db6e6e9744c486ac79bf9426d4ffe90a68fc0217c060e6a4bf0d634e1825a104e0fa1f3a32114683f3f3984e64744e8ea24115a1c
+0da1f06c7e92085d1c0da1f393c4e7f278f89c689cbe3a1a42f3138dd3cb2322749a713a981d0da2c5d715a81db239b1f97d07afc1aa01cc0da79d0d2aac4f11
+e608611aed09a2ddaa4f29edb6fa80629a5559604b757f5dc68156851c538503cdfa20a6aa768bdc391719499b51a42079a9ef8c739ed351483b53f14aa288f5
+c9ce2129d1e556f06ab3f54cd1cb9de29049de177b3c3d150955f9df7797dfef6269cfb5822b53fbd06d56b336aef68078a071056613badae3626287db195bdb
+f1ccfaa312cecf1e1ca773551feaacdad83a48c7e5cd81f686f56998d9de7d570596de00d853e6d148ba44b53a0db50d8183ce0043bbe8d3be293a50a7e67bfc
+9d51d3b717849aa31f869aa507889ade0f450f8b72359a155ba27df66051099a329a74f827bfed72cf2e0613139af8e0d4c11ea87ff1f56f34923b26b71040b0
+ecd35708b3855622ea7767de41f9e33175e399fad32a41290d478bfe93121debfe283efece39fec4b1f03748d534224e5687f6cd801e6682634c723ec1de13e8
+8aff763b1d178f56ed501bf6c938a02f7c055232997e563087b76593ab60e979b44a5b4ae2cfed22a3522153859d873d29ce59188c495d9c0b87d11865949495
+7809880e2bf09d91c62da5d7d7698f29c2d33ceeecd7537b77cc652bcc90ca553993267918097b103e06767dddf9844b8d7181baf7ae20517ffa753a48269de7
+36dd69e4715fdbec833a7713489bf1c139277e2cd4cdfb89ae3da6f580e2b12bc1d8f2c9a1c2de99bbf6b26d5ea70e432eb967e9d3b6a879053260d216c7176a
+532de39f46759fc30c98f46d7fe0fc420c8a12fe69cebd473f03166db37ca1463542fec1edfa932e633d3375a9f3b0d955d0f3fe62e0f8f987495d2cd8c3c98b
+e57a62fa525bf4f94f6906cc695e958e593df601ea891b742077a92dfac4ece5654c6adece8e31a97d667be226edcd5c6a833e29777919739a17c263cc691f13
+9fb839873297daa24fcd5d5ec6a8e61df418a3da27d35fb151fdbdef54988ff83c19bf4218799660adb2a11e989457b2e5033fbf9e4d3b78066a774177e16eaf
+59df78069d379eb655cd670c1b06678ba5db6eaf37c3cbb3a5ba3d36320a06d070c19a2f02e3b71f05616e45cad1a4dffd5fc745b0efcbe62bd91e0e50e3e236
+1eb8ec9a441f3702bfdd678ca89fce8fa84efbbd2633848c94521501ef9b6fcd8052d884d7d4cd67f751bed6ba7eb57f406fe41dc3a3af64ca7ed6083c55f074
+80c3545d3100282e7f5f0f0d8a5116316e59e95ffaed74135d1a1f6d3cd8f90e85e718d7f94ad21e967ef77f5e70f37f504b0708d111d268a1090000fc400000
+504b0304140008080800a26dbe4c000000000000000000000000150000004d4554412d494e462f6d616e69666573742e786d6cad92416ec3201045f73985c5de
+d0765521e3ec7a82f600080f0e121e108c23fbf6c5561cbbaa223552778c66f8fffd81e63c0dbeba42ca2ea062affc85558026740e7bc5be3e3fea77766e4fcd
+a0d159c824b74355ee61be978a8d0965d0d965897a802cc9c81001bb60c60190e4cf79b93addab03c01bbb49fb00d3a69b7ab909d93062a7a94cdf8c608a90dc
+d2d25e066b9d017950589dda53b547b0ce435dc6d3bc03d8d1fb3a6aba28261e72ed4b80cee99ae6088ae918bd332b90b862c7d71df06374de271d2fce64269e
+e1c840545e21f312e68137957c62693f256c02d282f5dfba99660f7fc56dc4af2fd57e03504b070800db977cf10000008d020000504b01021400140000080000
+a26dbe4c9f032ec42b0000002b0000000800000000000000000000000000000000006d696d6574797065504b01021400140008080800a26dbe4c9f6ee54e2b03
+0000361200000c000000000000000000000000005100000073657474696e67732e786d6c504b01021400140008080800a26dbe4ca84c77df6004000048110000
+0b00000000000000000000000000b6030000636f6e74656e742e786d6c504b01021400140008080800a26dbe4cd111d268a1090000fc4000000a000000000000
+000000000000004f0800007374796c65732e786d6c504b01021400140008080800a26dbe4c00db977cf10000008d020000150000000000000000000000000028
+1200004d4554412d494e462f6d616e69666573742e786d6c504b05060000000005000500240100005c1300000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000052006f006f007400200045006e007400720079000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000016000500ffffffffffffffff0100000071b78b44e2cfc447bcdf1fbf378e202c0000000000000000
+000000000000000000000000030000000001000000000000010043006f006d0070004f0062006a00000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000120002000200000003000000ffffffff000000000000000000000000000000000000000000000000
+00000000000000000000000000000000530000000000000001004f006c0065000000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000a000200ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000020000001400000000000000700072006f0070006500720074006900650073005f00730074007200650061006d00000000000000
+0000000000000000000000000000000000000000000000002400020004000000ffffffffffffffff000000000000000000000000000000000000000000000000
+0000000000000000000000000300000010000000000000007000610063006b006100670065005f00730074007200650061006d00000000000000000000000000
+0000000000000000000000000000000000000000000000001e000200ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+00000000000000000000000004000000961400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000feffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000feffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000feffffff0000000000000000}} \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/reqif-ole-odg.png b/sw/qa/extras/htmlexport/data/reqif-ole-odg.png
new file mode 100644
index 0000000000..66b76c74a1
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-ole-odg.png
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/reqif-ole-odg.xhtml b/sw/qa/extras/htmlexport/data/reqif-ole-odg.xhtml
new file mode 100644
index 0000000000..9e7be3ae88
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-ole-odg.xhtml
@@ -0,0 +1,9 @@
+<reqif-xhtml:div><reqif-xhtml:p><reqif-xhtml:br/>
+
+</reqif-xhtml:p>
+<reqif-xhtml:p><reqif-xhtml:object data="reqif-ole-odg.ole" type="text/rtf">
+<reqif-xhtml:object data="reqif-ole-odg.png" type="image/png" width="533" height="378"/>
+</reqif-xhtml:object><reqif-xhtml:br/>
+
+</reqif-xhtml:p>
+</reqif-xhtml:div>
diff --git a/sw/qa/extras/htmlexport/data/reqif-ole2.xhtml b/sw/qa/extras/htmlexport/data/reqif-ole2.xhtml
new file mode 100644
index 0000000000..716ecd1bda
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-ole2.xhtml
@@ -0,0 +1,5 @@
+<reqif-xhtml:div>
+ <reqif-xhtml:object data="ole2.ole" type="text/rtf">
+ <reqif-xhtml:object data="ole2.png" type="image/png">OLE Object</reqif-xhtml:object>
+ </reqif-xhtml:object>
+</reqif-xhtml:div>
diff --git a/sw/qa/extras/htmlexport/data/reqif-p.xhtml b/sw/qa/extras/htmlexport/data/reqif-p.xhtml
new file mode 100644
index 0000000000..304857d9a9
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-p.xhtml
@@ -0,0 +1,8 @@
+<reqif-xhtml:p>aaa<reqif-xhtml:br/>bbb</reqif-xhtml:p>
+<reqif-xhtml:table><reqif-xhtml:tr><reqif-xhtml:td>in table</reqif-xhtml:tr></reqif-xhtml:tr></reqif-xhtml:table>
+<reqif-xhtml:a href="http://libreoffice.org/">http://libreoffice.org</reqif-xhtml:a>
+<reqif-xhtml:span style="text-decoration: underline">u</reqif-xhtml:span>
+<reqif-xhtml:strong>s</reqif-xhtml:strong>
+<reqif-xhtml:strike>s</reqif-xhtml:strike>
+<reqif-xhtml:font color="#ce181e">s</reqif-xhtml:font>
+<reqif-xhtml:a name="Bookmark 1"></reqif-xhtml:a>
diff --git a/sw/qa/extras/htmlexport/data/reqif-png-img.xhtml b/sw/qa/extras/htmlexport/data/reqif-png-img.xhtml
new file mode 100644
index 0000000000..637a7c2ac4
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-png-img.xhtml
@@ -0,0 +1,4 @@
+<reqif-xhtml:div><reqif-xhtml:br/>
+ <reqif-xhtml:object data="reqif-ole-img.png?test=true" type="image/png">OLE Object</reqif-xhtml:object>
+</reqif-xhtml:div>
+
diff --git a/sw/qa/extras/htmlexport/data/reqif-table.xhtml b/sw/qa/extras/htmlexport/data/reqif-table.xhtml
new file mode 100644
index 0000000000..1bf1f0d937
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-table.xhtml
@@ -0,0 +1,9 @@
+<reqif-xhtml:div><table border="1" style="width:100%">
+ <tr>
+ <th bgcolor="#888888">A1</th>
+ </tr>
+ <tr>
+ <td>A2</td>
+ </tr>
+</table>
+</reqif-xhtml:div>
diff --git a/sw/qa/extras/htmlexport/data/reqif-table2.odt b/sw/qa/extras/htmlexport/data/reqif-table2.odt
new file mode 100644
index 0000000000..772dde0dd6
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-table2.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/reqif-transparent-tif-img.odt b/sw/qa/extras/htmlexport/data/reqif-transparent-tif-img.odt
new file mode 100644
index 0000000000..278cf9ebc8
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/reqif-transparent-tif-img.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/skipimage-embedded-document.docx b/sw/qa/extras/htmlexport/data/skipimage-embedded-document.docx
new file mode 100644
index 0000000000..f48935ad44
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/skipimage-embedded-document.docx
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/skipimage-embedded.doc b/sw/qa/extras/htmlexport/data/skipimage-embedded.doc
new file mode 100644
index 0000000000..b4b57ec5f5
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/skipimage-embedded.doc
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/sub_li_and_ctd.fodt b/sw/qa/extras/htmlexport/data/sub_li_and_ctd.fodt
new file mode 100644
index 0000000000..b4a3977926
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/sub_li_and_ctd.fodt
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+ <office:text>
+ <text:list>
+ <text:list-item>
+ <text:p>l1</text:p>
+ <text:p>l1_ctd1</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p>l2</text:p>
+ </text:list-item>
+ <text:list-item>
+ <text:p>l2</text:p>
+ </text:list-item>
+ </text:list>
+ <text:p>l1_ctd2</text:p>
+ <text:list>
+ <text:list-item>
+ <text:list>
+ <text:list-item>
+ <text:p>l3</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ </text:list>
+ <text:p>l1_ctd3</text:p>
+ </text:list-item>
+ </text:list>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/tableRight.fodt b/sw/qa/extras/htmlexport/data/tableRight.fodt
new file mode 100644
index 0000000000..374364750f
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/tableRight.fodt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:automatic-styles>
+ <style:style style:name="Table1" style:family="table">
+ <style:table-properties style:width="10cm" table:align="right"/>
+ </style:style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <text:p>This is a right aligned table:</text:p>
+ <table:table table:style-name="Table1">
+ <table:table-column table:number-columns-repeated="2"/>
+ <table:table-row>
+ <table:table-cell/>
+ <table:table-cell/>
+ </table:table-row>
+ </table:table>
+ <text:p/>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/table_cell_padding.fodt b/sw/qa/extras/htmlexport/data/table_cell_padding.fodt
new file mode 100644
index 0000000000..059a37b9da
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/table_cell_padding.fodt
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:automatic-styles>
+ <style:style style:name="TableCell" style:family="table-cell">
+ <style:table-cell-properties fo:padding="1.27cm" fo:border="none"/>
+ </style:style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <table:table table:name="Table1">
+ <table:table-column/>
+ <table:table-column/>
+ <table:table-row>
+ <table:table-cell table:style-name="TableCell" office:value-type="string">
+ <text:p>A</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="TableCell" office:value-type="string">
+ <text:p>B</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="TableCell" office:value-type="string">
+ <text:p>C</text:p>
+ </table:table-cell>
+ <table:table-cell table:style-name="TableCell" office:value-type="string">
+ <text:p>D</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p/>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/sw/qa/extras/htmlexport/data/table_with_wide_horizontal_border.fodt b/sw/qa/extras/htmlexport/data/table_with_wide_horizontal_border.fodt
new file mode 100644
index 0000000000..a3c53a0707
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/table_with_wide_horizontal_border.fodt
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:officeooo="http://openoffice.org/2009/office" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:automatic-styles>
+ <style:style style:name="Table1.A1" style:family="table-cell">
+ <style:table-cell-properties fo:border-bottom="1.5pt solid"/>
+ </style:style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <table:table>
+ <table:table-column/>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p>A1</text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell office:value-type="string">
+ <text:p>A2</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p/>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/tdf126879.odt b/sw/qa/extras/htmlexport/data/tdf126879.odt
new file mode 100644
index 0000000000..8002e93da7
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/tdf126879.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/tdf132739.odt b/sw/qa/extras/htmlexport/data/tdf132739.odt
new file mode 100644
index 0000000000..6156aca93b
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/tdf132739.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/tdf155871.fodt b/sw/qa/extras/htmlexport/data/tdf155871.fodt
new file mode 100644
index 0000000000..97e29fbe69
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/tdf155871.fodt
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+ <office:text>
+ <text:list>
+ <text:list-item>
+ <text:p>foo</text:p>
+ <text:list>
+ <text:list-item>
+ <text:p>bar</text:p>
+ </text:list-item>
+ </text:list>
+ </text:list-item>
+ <text:list-item>
+ <text:p>baz</text:p>
+ </text:list-item>
+ </text:list>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/tdf66822.odt b/sw/qa/extras/htmlexport/data/tdf66822.odt
new file mode 100644
index 0000000000..88cc750cba
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/tdf66822.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/tdf76291.odt b/sw/qa/extras/htmlexport/data/tdf76291.odt
new file mode 100644
index 0000000000..68588c8763
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/tdf76291.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/tdf83890.odt b/sw/qa/extras/htmlexport/data/tdf83890.odt
new file mode 100644
index 0000000000..fcfab68f93
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/tdf83890.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/tdf90905.odt b/sw/qa/extras/htmlexport/data/tdf90905.odt
new file mode 100644
index 0000000000..19a51bdf8f
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/tdf90905.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/test_no_space_preserve.fodt b/sw/qa/extras/htmlexport/data/test_no_space_preserve.fodt
new file mode 100644
index 0000000000..e0d9a3506e
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/test_no_space_preserve.fodt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+ <office:text>
+ <text:p>No special spaces</text:p>
+ <text:p><text:s/>Leading space</text:p>
+ <text:p>Trailing space </text:p>
+ <text:p>Double <text:s/>space</text:p>
+ <text:p><text:line-break/>Leading/trailing breaks<text:line-break/></text:p>
+ <text:p><text:line-break/> Leading break + space</text:p>
+ <text:p>Trailing space + break <text:line-break/></text:p>
+ <text:p>Middle<text:line-break/>break</text:p>
+ <text:p>Middle space <text:line-break/>+ break</text:p>
+ <text:p>Middle break<text:line-break/> + space</text:p>
+ <text:p>Trailing space and SVG <draw:frame text:anchor-type="as-char" svg:width="5.59mm" svg:height="5.59mm" draw:z-index="0"><draw:image draw:mime-type="image/svg+xml">
+ <office:binary-data>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB4bWxucz0iaHR0
+ cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDIw
+ IDIwIiBzdHJva2U9ImJsYWNrIj4KPHBhdGggZD0iTTEsMUwxOSwxOSIvPgo8L3N2Zz4=
+ </office:binary-data>
+ </draw:image>
+ </draw:frame></text:p>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/textAndImage.docx b/sw/qa/extras/htmlexport/data/textAndImage.docx
new file mode 100644
index 0000000000..adad462793
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/textAndImage.docx
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/transparent-image.odt b/sw/qa/extras/htmlexport/data/transparent-image.odt
new file mode 100644
index 0000000000..0c5fb8de07
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/transparent-image.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/transparent.png b/sw/qa/extras/htmlexport/data/transparent.png
new file mode 100644
index 0000000000..936980b0a1
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/transparent.png
Binary files differ
diff --git a/sw/qa/extras/htmlexport/data/twoListsWithSameStyle.fodt b/sw/qa/extras/htmlexport/data/twoListsWithSameStyle.fodt
new file mode 100644
index 0000000000..a5dc0f014d
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/twoListsWithSameStyle.fodt
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+ <office:text>
+ <text:list text:style-name="Numbering 123">
+ <text:list-header>
+ <text:p/>
+ </text:list-header>
+ </text:list>
+ <text:p/>
+ <text:list text:style-name="Numbering 123">
+ <text:list-header>
+ <text:p/>
+ </text:list-header>
+ </text:list>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/data/xhtml-css.odt b/sw/qa/extras/htmlexport/data/xhtml-css.odt
new file mode 100644
index 0000000000..a094202e97
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/xhtml-css.odt
Binary files differ
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
new file mode 100644
index 0000000000..1bd883be11
--- /dev/null
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -0,0 +1,3037 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#include <memory>
+#include <string_view>
+
+#include <com/sun/star/document/XEmbeddedObjectSupplier2.hpp>
+#include <com/sun/star/document/XTypeDetection.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/io/XActiveDataStreamer.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/table/TableBorder2.hpp>
+#include <com/sun/star/text/XTextTablesSupplier.hpp>
+#include <com/sun/star/text/XTextTable.hpp>
+#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/packages/zip/ZipFileAccess.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+
+#include <test/htmltesttools.hxx>
+#include <tools/urlobj.hxx>
+#include <svtools/rtfkeywd.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <svtools/parrtf.hxx>
+#include <rtl/strbuf.hxx>
+#include <svtools/rtftoken.h>
+#include <filter/msfilter/rtfutil.hxx>
+#include <sot/storage.hxx>
+#include <vcl/svapp.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <svtools/htmlcfg.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <vcl/dibtools.hxx>
+#include <o3tl/string_view.hxx>
+#include <editeng/brushitem.hxx>
+#include <comphelper/scopeguard.hxx>
+
+#include <swmodule.hxx>
+#include <swdll.hxx>
+#include <usrpref.hxx>
+#include <wrtsh.hxx>
+#include <ndtxt.hxx>
+#include <paratr.hxx>
+#include <docsh.hxx>
+#include <unotxdoc.hxx>
+#include <formatlinebreak.hxx>
+#include <itabenum.hxx>
+
+namespace
+{
+/// Test RTF parser that just extracts a single OLE2 object from a file.
+class TestReqIfRtfReader : public SvRTFParser
+{
+public:
+ TestReqIfRtfReader(SvStream& rStream);
+ void NextToken(int nToken) override;
+ bool WriteObjectData(SvStream& rOLE);
+ tools::Long GetObjw() const { return m_nObjw; }
+ tools::Long GetObjh() const { return m_nObjh; }
+ int getWmetafile() const { return m_nWmetafile; }
+
+private:
+ bool m_bInObjData = false;
+ OStringBuffer m_aHex;
+ tools::Long m_nObjw = 0;
+ tools::Long m_nObjh = 0;
+ int m_nWmetafile = 0;
+};
+
+TestReqIfRtfReader::TestReqIfRtfReader(SvStream& rStream)
+ : SvRTFParser(rStream)
+{
+}
+
+void TestReqIfRtfReader::NextToken(int nToken)
+{
+ switch (nToken)
+ {
+ case '}':
+ m_bInObjData = false;
+ break;
+ case RTF_TEXTTOKEN:
+ if (m_bInObjData)
+ m_aHex.append(OUStringToOString(aToken, RTL_TEXTENCODING_ASCII_US));
+ break;
+ case RTF_OBJDATA:
+ m_bInObjData = true;
+ break;
+ case RTF_OBJW:
+ m_nObjw = nTokenValue;
+ break;
+ case RTF_OBJH:
+ m_nObjh = nTokenValue;
+ break;
+ case RTF_WMETAFILE:
+ m_nWmetafile = nTokenValue;
+ break;
+ }
+}
+
+bool TestReqIfRtfReader::WriteObjectData(SvStream& rOLE)
+{
+ OString aObjdata = m_aHex.makeStringAndClear();
+
+ SvMemoryStream aStream;
+ int b = 0;
+ int count = 2;
+
+ // Feed the destination text to a stream.
+ for (int i = 0; i < aObjdata.getLength(); ++i)
+ {
+ char ch = aObjdata[i];
+ if (ch != 0x0d && ch != 0x0a)
+ {
+ b = b << 4;
+ sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
+ if (parsed == -1)
+ return false;
+ b += parsed;
+ count--;
+ if (!count)
+ {
+ aStream.WriteChar(b);
+ count = 2;
+ b = 0;
+ }
+ }
+ }
+
+ aStream.Seek(0);
+ rOLE.WriteStream(aStream);
+ return true;
+}
+
+/// Parser for [MS-OLEDS] 2.2.5 EmbeddedObject, aka OLE1.
+struct OLE1Reader
+{
+ sal_uInt32 m_nNativeDataSize;
+ std::vector<char> m_aNativeData;
+ sal_uInt32 m_nPresentationDataSize;
+
+ OLE1Reader(SvStream& rStream);
+};
+
+OLE1Reader::OLE1Reader(SvStream& rStream)
+{
+ // Skip ObjectHeader, see [MS-OLEDS] 2.2.4.
+ rStream.Seek(0);
+ CPPUNIT_ASSERT(rStream.remainingSize());
+ sal_uInt32 nData;
+ rStream.ReadUInt32(nData); // OLEVersion
+ rStream.ReadUInt32(nData); // FormatID
+ rStream.ReadUInt32(nData); // ClassName
+ rStream.SeekRel(nData);
+ rStream.ReadUInt32(nData); // TopicName
+ rStream.SeekRel(nData);
+ rStream.ReadUInt32(nData); // ItemName
+ rStream.SeekRel(nData);
+
+ rStream.ReadUInt32(m_nNativeDataSize);
+ m_aNativeData.resize(m_nNativeDataSize);
+ rStream.ReadBytes(m_aNativeData.data(), m_aNativeData.size());
+
+ rStream.ReadUInt32(nData); // OLEVersion for presentation data
+ CPPUNIT_ASSERT(rStream.good());
+ rStream.ReadUInt32(nData); // FormatID
+ rStream.ReadUInt32(nData); // ClassName
+ rStream.SeekRel(nData);
+ rStream.ReadUInt32(nData); // Width
+ rStream.ReadUInt32(nData); // Height
+ rStream.ReadUInt32(nData); // PresentationDataSize
+ m_nPresentationDataSize = nData;
+}
+}
+
+/// Covers sw/source/filter/html/wrthtml.cxx and related fixes.
+class HtmlExportTest : public SwModelTestBase, public HtmlTestTools
+{
+public:
+ HtmlExportTest()
+ : SwModelTestBase("/sw/qa/extras/htmlexport/data/", "HTML (StarWriter)")
+ {
+ }
+
+ /// Wraps an RTF fragment into a complete RTF file, so an RTF parser can handle it.
+ static void wrapRtfFragment(const OUString& rURL, SvMemoryStream& rStream)
+ {
+ SvFileStream aRtfStream(rURL, StreamMode::READ);
+ rStream.WriteOString("{\\rtf1");
+ rStream.WriteStream(aRtfStream);
+ rStream.WriteOString("}");
+ rStream.Seek(0);
+ }
+};
+
+/// HTML export of the sw doc model tests.
+class SwHtmlDomExportTest : public SwModelTestBase, public HtmlTestTools
+{
+public:
+ SwHtmlDomExportTest()
+ : SwModelTestBase("/sw/qa/extras/htmlexport/data/")
+ {
+ }
+
+ OUString GetObjectPath(const OUString& ext);
+ /// Get the .ole path, assuming maTempFile is an XHTML export result.
+ OUString GetOlePath() { return GetObjectPath(u".ole"_ustr); }
+ OUString GetPngPath() { return GetObjectPath(u".png"_ustr); }
+ /// Parse the ole1 data out of an RTF fragment URL.
+ void ParseOle1FromRtfUrl(const OUString& rRtfUrl, SvMemoryStream& rOle1);
+ /// Export using the C++ HTML export filter, with xhtmlns=reqif-xhtml.
+ void ExportToReqif();
+ /// Import using the C++ HTML import filter, with xhtmlns=reqif-xhtml.
+ void ImportFromReqif(const OUString& rUrl);
+ /// Export using the C++ HTML export filter
+ void ExportToHTML();
+};
+
+OUString SwHtmlDomExportTest::GetObjectPath(const OUString& ext)
+{
+ assert(ext.startsWith("."));
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+ OUString aOlePath
+ = getXPath(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object"_ostr,
+ "data"_ostr);
+ CPPUNIT_ASSERT(aOlePath.endsWith(ext));
+ INetURLObject aUrl(maTempFile.GetURL());
+ aUrl.setBase(aOlePath.subView(0, aOlePath.getLength() - ext.getLength()));
+ aUrl.setExtension(ext.subView(1));
+ return aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+}
+
+void SwHtmlDomExportTest::ParseOle1FromRtfUrl(const OUString& rRtfUrl, SvMemoryStream& rOle1)
+{
+ SvMemoryStream aRtf;
+ HtmlExportTest::wrapRtfFragment(rRtfUrl, aRtf);
+ tools::SvRef<TestReqIfRtfReader> xReader(new TestReqIfRtfReader(aRtf));
+ CPPUNIT_ASSERT(xReader->CallParser() != SvParserState::Error);
+ CPPUNIT_ASSERT(xReader->WriteObjectData(rOle1));
+ CPPUNIT_ASSERT(rOle1.Tell());
+}
+
+void SwHtmlDomExportTest::ExportToReqif()
+{
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ save("HTML (StarWriter)");
+}
+
+void SwHtmlDomExportTest::ExportToHTML()
+{
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+}
+
+void SwHtmlDomExportTest::ImportFromReqif(const OUString& rUrl)
+{
+ uno::Sequence<beans::PropertyValue> aLoadProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ };
+ mxComponent = loadFromDesktop(rUrl, "com.sun.star.text.TextDocument", aLoadProperties);
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testFdo81276)
+{
+ auto verify = [this]() {
+ uno::Reference<container::XNameAccess> xPageStyles(getStyles("PageStyles"));
+ uno::Reference<beans::XPropertySet> xStyle(xPageStyles->getByName("HTML"), uno::UNO_QUERY);
+ // some rounding going on here?
+ CPPUNIT_ASSERT(abs(sal_Int32(29700) - getProperty<sal_Int32>(xStyle, "Width")) < 10);
+ CPPUNIT_ASSERT(abs(sal_Int32(21006) - getProperty<sal_Int32>(xStyle, "Height")) < 10);
+ CPPUNIT_ASSERT(abs(sal_Int32(500) - getProperty<sal_Int32>(xStyle, "LeftMargin")) < 10);
+ CPPUNIT_ASSERT(abs(sal_Int32(500) - getProperty<sal_Int32>(xStyle, "RightMargin")) < 10);
+ CPPUNIT_ASSERT(abs(sal_Int32(2000) - getProperty<sal_Int32>(xStyle, "TopMargin")) < 10);
+ CPPUNIT_ASSERT(abs(sal_Int32(500) - getProperty<sal_Int32>(xStyle, "BottomMargin")) < 10);
+ };
+ setImportFilterName(mpFilter);
+ createSwDoc("fdo81276.html");
+ verify();
+ saveAndReload(mpFilter);
+ verify();
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testFdo62336)
+{
+ // The problem was essentially a crash during table export as docx/rtf/html
+ // If calc-layout is enabled, the crash does not occur, that's why loadFromFile/save is used
+ loadFromFile(u"fdo62336.docx");
+ save("HTML (StarWriter)");
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testFdo86857)
+{
+ auto verify = [this]() {
+ // problem was that background color on page style was not exported
+ uno::Reference<container::XNameAccess> xPageStyles(getStyles("PageStyles"));
+ uno::Reference<beans::XPropertySet> xStyle(xPageStyles->getByName("HTML"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, getProperty<Color>(xStyle, "BackColor"));
+ // check that table background color works, which still uses RES_BACKGROUND
+ uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
+ uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());
+ uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xCell(xTable->getCellByName("A1"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(Color(0x66ffff), getProperty<Color>(xCell, "BackColor"));
+ };
+
+ setImportFilterName(mpFilter);
+ createSwDoc("fdo86857.html");
+ verify();
+ saveAndReload(mpFilter);
+ verify();
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testCharacterBorder)
+{
+ // FIXME if padding-top gets exported as inches, not cms, we get rounding errors.
+ SwGlobals::ensure(); // make sure that SW_MOD() is not 0
+ SwMasterUsrPref* pPref = const_cast<SwMasterUsrPref*>(SW_MOD()->GetUsrPref(false));
+ FieldUnit eUnit = pPref->GetMetric();
+ pPref->SetMetric(FieldUnit::CM);
+ comphelper::ScopeGuard g([pPref, eUnit]() { pPref->SetMetric(eUnit); });
+
+ auto verify = [this]() {
+ CPPUNIT_ASSERT_EQUAL(1, getPages());
+
+ uno::Reference<beans::XPropertySet> xRun(getRun(getParagraph(1), 1), uno::UNO_QUERY);
+ // Different Border
+ {
+ CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0x6666FF, 12, 12, 12, 3, 37),
+ getProperty<table::BorderLine2>(xRun, "CharTopBorder"));
+ CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF9900, 0, 99, 0, 2, 99),
+ getProperty<table::BorderLine2>(xRun, "CharLeftBorder"));
+ CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF0000, 0, 169, 0, 1, 169),
+ getProperty<table::BorderLine2>(xRun, "CharBottomBorder"));
+ CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0x0000FF, 0, 169, 0, 0, 169),
+ getProperty<table::BorderLine2>(xRun, "CharRightBorder"));
+ }
+
+ // Different Padding
+ {
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(450),
+ getProperty<sal_Int32>(xRun, "CharTopBorderDistance"));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(550),
+ getProperty<sal_Int32>(xRun, "CharLeftBorderDistance"));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(150),
+ getProperty<sal_Int32>(xRun, "CharBottomBorderDistance"));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(250),
+ getProperty<sal_Int32>(xRun, "CharRightBorderDistance"));
+ }
+
+ // No shadow
+ };
+ createSwDoc("charborder.odt");
+ verify();
+ saveAndReload(mpFilter);
+ verify();
+}
+
+#define DECLARE_HTMLEXPORT_TEST(TestName, filename) \
+ DECLARE_SW_EXPORT_TEST(TestName, filename, nullptr, HtmlExportTest)
+
+DECLARE_HTMLEXPORT_TEST(testExportOfImages, "textAndImage.docx")
+{
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPath(pDoc, "/html/body"_ostr, 1);
+ assertXPath(pDoc, "/html/body/p/img"_ostr, 1);
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testExportOfImagesWithSkipImagesEnabled)
+{
+ createSwDoc("textAndImage.docx");
+ setFilterOptions("SkipImages");
+ save(mpFilter);
+
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPath(pDoc, "/html/body"_ostr, 1);
+ assertXPath(pDoc, "/html/body/p/img"_ostr, 0);
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testSkipImagesEmbedded)
+{
+ createSwDoc("skipimage-embedded.doc");
+ setFilterOptions("SkipImages");
+ save(mpFilter);
+
+ // Embedded spreadsheet was exported as image, so content was lost. Make
+ // sure it's exported as HTML instead.
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ // This was 0.
+ assertXPath(pDoc, "//table"_ostr, 1);
+ // This was 2, the HTML header was in the document two times.
+ assertXPath(pDoc, "//meta[@name='generator']"_ostr, 1);
+ // This was 0, <table> was directly under <p>, which caused errors in the parser.
+ assertXPath(pDoc, "//span/table"_ostr, 1);
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testSkipImagesEmbeddedDocument)
+{
+ createSwDoc("skipimage-embedded-document.docx");
+ setFilterOptions("SkipImages");
+ save(mpFilter);
+
+ // Similar to testSkipImagesEmbedded, but with an embedded Writer object,
+ // not a Calc one, and this time OOXML, not WW8.
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ // This was 2, the HTML header was in the document two times.
+ assertXPath(pDoc, "//meta[@name='generator']"_ostr, 1);
+ // Text of embedded document was missing.
+ assertXPathContent(pDoc, "/html/body/p/span/p/span"_ostr, "Inner.");
+}
+
+DECLARE_HTMLEXPORT_TEST(testExportImageProperties, "HTMLImage.odt")
+{
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPath(pDoc, "/html/body"_ostr, 1);
+
+ assertXPath(pDoc, "/html/body/p/map/area"_ostr, "shape"_ostr, "poly");
+ assertXPath(pDoc, "/html/body/p/map/area"_ostr, "href"_ostr, "http://www.microsoft.com/");
+ assertXPath(pDoc, "/html/body/p/map/area"_ostr, "target"_ostr, "_self");
+ assertXPath(pDoc, "/html/body/p/map/area"_ostr, "alt"_ostr, "microsoft");
+
+ assertXPath(pDoc, "/html/body/p/a"_ostr, 1);
+ assertXPath(pDoc, "/html/body/p/a"_ostr, "href"_ostr, "http://www.google.com/");
+
+ assertXPath(pDoc, "/html/body/p/a/font"_ostr, 1);
+ assertXPath(pDoc, "/html/body/p/a/font"_ostr, "color"_ostr, "#ff0000");
+
+ assertXPath(pDoc, "/html/body/p/a/font/img"_ostr, 1);
+ assertXPath(pDoc, "/html/body/p/a/font/img"_ostr, "name"_ostr, "Text");
+ assertXPath(pDoc, "/html/body/p/a/font/img"_ostr, "alt"_ostr, "Four colors");
+ assertXPath(pDoc, "/html/body/p/a/font/img"_ostr, "align"_ostr, "middle");
+
+ // Probably the DPI in OSX is different and Twip -> Pixel conversion produces
+ // different results - so disable OSX for now.
+ //
+ // It would make sense to switch to use CSS and use "real world" units instead
+ // i.e. (style="margin: 0cm 1.5cm; width: 1cm; height: 1cm")
+
+#if 0 // disabled as it depends that the system DPI is set to 96
+ assertXPath(pDoc, "/html/body/p/a/font/img", "hspace", "38");
+ assertXPath(pDoc, "/html/body/p/a/font/img", "vspace", "19");
+ assertXPath(pDoc, "/html/body/p/a/font/img", "width", "222");
+ assertXPath(pDoc, "/html/body/p/a/font/img", "height", "222");
+ assertXPath(pDoc, "/html/body/p/a/font/img", "border", "3");
+#endif
+
+ assertXPath(pDoc, "/html/body/p/a/font/img"_ostr, "usemap"_ostr, "#map1");
+}
+
+DECLARE_HTMLEXPORT_TEST(testExportCheckboxRadioButtonState, "checkbox-radiobutton.doc")
+{
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPath(pDoc, "/html/body"_ostr, 1);
+ assertXPath(pDoc, "/html/body/p[1]/input"_ostr, "type"_ostr, "checkbox");
+ assertXPath(pDoc, "/html/body/p[1]/input"_ostr, "checked"_ostr, "checked");
+ assertXPath(pDoc, "/html/body/p[2]/input"_ostr, "type"_ostr, "checkbox");
+ assertXPathNoAttribute(pDoc, "/html/body/p[2]/input"_ostr, "checked"_ostr);
+ assertXPath(pDoc, "/html/body/form/p[1]/input"_ostr, "type"_ostr, "checkbox");
+ assertXPath(pDoc, "/html/body/form/p[1]/input"_ostr, "checked"_ostr, "checked");
+ assertXPath(pDoc, "/html/body/form/p[2]/input"_ostr, "type"_ostr, "checkbox");
+ assertXPathNoAttribute(pDoc, "/html/body/form/p[2]/input"_ostr, "checked"_ostr);
+ assertXPath(pDoc, "/html/body/form/p[3]/input"_ostr, "type"_ostr, "radio");
+ assertXPath(pDoc, "/html/body/form/p[3]/input"_ostr, "checked"_ostr, "checked");
+ assertXPath(pDoc, "/html/body/form/p[4]/input"_ostr, "type"_ostr, "radio");
+ assertXPathNoAttribute(pDoc, "/html/body/form/p[4]/input"_ostr, "checked"_ostr);
+}
+
+DECLARE_HTMLEXPORT_TEST(testExportUrlEncoding, "tdf76291.odt")
+{
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ // Test URI encoded hyperlink with Chinese characters
+ assertXPath(pDoc, "/html/body/p/a"_ostr, "href"_ostr,
+ "http://www.youtube.com/results?search_query=%E7%B2%B5%E8%AA%9Emv&sm=12");
+}
+
+DECLARE_HTMLEXPORT_TEST(testExportInternalUrl, "tdf90905.odt")
+{
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ // Internal url should be valid
+ assertXPath(pDoc, "/html/body/p[1]/a"_ostr, "href"_ostr, "#0.0.1.Text|outline");
+ assertXPath(pDoc, "/html/body/p[2]/a"_ostr, "href"_ostr, "#bookmark");
+}
+
+DECLARE_HTMLEXPORT_TEST(testExportImageBulletList, "tdf66822.odt")
+{
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ // Encoded base64 SVG bullet should match and render on browser
+ assertXPath(pDoc, "/html/body/ul"_ostr, 1);
+ assertXPath(
+ pDoc, "/html/body/ul"_ostr, "style"_ostr,
+ "list-style-image: url(data:image/svg+xml;base64,"
+ "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3"
+ "RyYXRvciAxMi4wLjEsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDUxNDQ4KSAg"
+ "LS0+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm"
+ "9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiIFsNCgk8IUVOVElUWSBuc19zdmcgImh0dHA6Ly93d3cu"
+ "dzMub3JnLzIwMDAvc3ZnIj4NCgk8IUVOVElUWSBuc194bGluayAiaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluay"
+ "I+DQpdPg0KPHN2ZyAgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9IiZuc19zdmc7IiB4bWxuczp4bGlu"
+ "az0iJm5zX3hsaW5rOyIgd2lkdGg9IjE0LjAwOCIgaGVpZ2h0PSIxNC4wMSINCgkgdmlld0JveD0iMCAwIDE0LjAwOC"
+ "AxNC4wMSIgb3ZlcmZsb3c9InZpc2libGUiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDE0LjAwOCAxNC4wMSIg"
+ "eG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cmFkaWFsR3JhZGllbnQgaWQ9IlhNTElEXzRfIiBjeD0iNy4wMD"
+ "Q0IiBjeT0iNy4wMDQ5IiByPSI3LjAwNDQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4NCgkJPHN0b3Ag"
+ "IG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzM1REIzNSIvPg0KCQk8c3RvcCAgb2Zmc2V0PSIxIiBzdHlsZT"
+ "0ic3RvcC1jb2xvcjojMDBBMDAwIi8+DQoJPC9yYWRpYWxHcmFkaWVudD4NCgk8Y2lyY2xlIGZpbGw9InVybCgjWE1M"
+ "SURfNF8pIiBjeD0iNy4wMDQiIGN5PSI3LjAwNSIgcj0iNy4wMDQiLz4NCgk8ZGVmcz4NCgkJPGZpbHRlciBpZD0iQW"
+ "RvYmVfT3BhY2l0eU1hc2tGaWx0ZXIiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeD0iMy40ODEiIHk9IjAu"
+ "NjkzIiB3aWR0aD0iNi45ODgiIGhlaWdodD0iMy44OTMiPg0KCQkJPGZlQ29sb3JNYXRyaXggIHR5cGU9Im1hdHJpeC"
+ "IgdmFsdWVzPSIxIDAgMCAwIDAgIDAgMSAwIDAgMCAgMCAwIDEgMCAwICAwIDAgMCAxIDAiLz4NCgkJPC9maWx0ZXI+"
+ "DQoJPC9kZWZzPg0KCTxtYXNrIG1hc2tVbml0cz0idXNlclNwYWNlT25Vc2UiIHg9IjMuNDgxIiB5PSIwLjY5MyIgd2"
+ "lkdGg9IjYuOTg4IiBoZWlnaHQ9IjMuODkzIiBpZD0iWE1MSURfNV8iPg0KCQk8ZyBmaWx0ZXI9InVybCgjQWRvYmVf"
+ "T3BhY2l0eU1hc2tGaWx0ZXIpIj4NCgkJCTxsaW5lYXJHcmFkaWVudCBpZD0iWE1MSURfNl8iIGdyYWRpZW50VW5pdH"
+ "M9InVzZXJTcGFjZU9uVXNlIiB4MT0iNy4xMjIxIiB5MT0iMC4xMDMiIHgyPSI3LjEyMjEiIHkyPSI1LjIzNDQiPg0K"
+ "CQkJCTxzdG9wICBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiNGRkZGRkYiLz4NCgkJCQk8c3RvcCAgb2Zmc2"
+ "V0PSIxIiBzdHlsZT0ic3RvcC1jb2xvcjojMDAwMDAwIi8+DQoJCQk8L2xpbmVhckdyYWRpZW50Pg0KCQkJPHJlY3Qg"
+ "eD0iMy4xOTkiIHk9IjAuMzM5IiBvcGFjaXR5PSIwLjciIGZpbGw9InVybCgjWE1MSURfNl8pIiB3aWR0aD0iNy44ND"
+ "YiIGhlaWdodD0iNC42MDEiLz4NCgkJPC9nPg0KCTwvbWFzaz4NCgk8ZWxsaXBzZSBtYXNrPSJ1cmwoI1hNTElEXzVf"
+ "KSIgZmlsbD0iI0ZGRkZGRiIgY3g9IjYuOTc1IiBjeT0iMi42NCIgcng9IjMuNDk0IiByeT0iMS45NDYiLz4NCjwvZz"
+ "4NCjwvc3ZnPg0K);");
+}
+
+DECLARE_HTMLEXPORT_TEST(testTdf83890, "tdf83890.odt")
+{
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPath(pDoc, "/html/body/ol[2]/ol"_ostr, "start"_ostr, "2");
+}
+
+DECLARE_HTMLEXPORT_TEST(testExtbChars, "extb.html")
+{
+ OUString aExpected(u"\U00024b62"_ustr);
+ // Assert that UTF8 encoded non-BMP Unicode character is correct
+ uno::Reference<text::XTextRange> xTextRange1 = getRun(getParagraph(1), 1);
+ CPPUNIT_ASSERT_EQUAL(aExpected, xTextRange1->getString());
+
+ // Assert that non-BMP Unicode in character entity format is correct
+ uno::Reference<text::XTextRange> xTextRange2 = getRun(getParagraph(2), 1);
+ CPPUNIT_ASSERT_EQUAL(aExpected, xTextRange2->getString());
+}
+
+DECLARE_HTMLEXPORT_TEST(testNormalImageExport, "textAndImage.docx")
+{
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPath(pDoc, "/html/body"_ostr, 1);
+
+ // the HTML export normally does not embed the images
+ OUString imgSrc = getXPath(pDoc, "/html/body/p/img"_ostr, "src"_ostr);
+ CPPUNIT_ASSERT(imgSrc.endsWith(".png"));
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testEmbedImagesEnabled)
+{
+ createSwDoc("textAndImage.docx");
+ setFilterOptions("EmbedImages");
+ save(mpFilter);
+
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPath(pDoc, "/html/body"_ostr, 1);
+
+ // the HTML export normally does not embed the images, but here the test
+ // name triggers setting of the "EmbedImages" filter option, meaning the
+ // image will not be a separate PNG, but an embedded base64 encoded
+ // version of that
+ OUString imgSrc = getXPath(pDoc, "/html/body/p/img"_ostr, "src"_ostr);
+ CPPUNIT_ASSERT(imgSrc.startsWith("data:image/png;base64,"));
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testXHTML)
+{
+ createSwWebDoc("hello.html");
+ setFilterOptions("XHTML");
+ save(mpFilter);
+
+ OString aExpected("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML"_ostr);
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ OString aActual(read_uInt8s_ToOString(*pStream, aExpected.getLength()));
+ // This was HTML, not XHTML.
+ CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
+
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+ // This was lang, not xml:lang.
+ assertXPath(pDoc, "/html/body"_ostr, "xml:lang"_ostr, "en-US");
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testReqIfParagraph)
+{
+ setImportFilterOptions("xhtmlns=reqif-xhtml");
+ setImportFilterName("HTML (StarWriter)");
+ createSwDoc("reqif-p.xhtml");
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ save(mpFilter);
+
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+
+ OString aExpected = "<reqif-xhtml:div><reqif-xhtml:p>aaa<reqif-xhtml:br/>\nbbb"
+ "</reqif-xhtml:p>" SAL_NEWLINE_STRING
+ // This was '<table' instead.
+ "<reqif-xhtml:table"_ostr;
+
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ pStream->Seek(0);
+ OString aActual(read_uInt8s_ToOString(*pStream, aExpected.getLength()));
+ // This was a HTML header, like '<!DOCTYPE html ...'.
+ CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
+
+ // This was "<a", was not found.
+ CPPUNIT_ASSERT(aStream.indexOf("<reqif-xhtml:a") != -1);
+
+ // This was "<u>" instead of CSS.
+ CPPUNIT_ASSERT(aStream.indexOf("<reqif-xhtml:span style=\"text-decoration: underline\"") != -1);
+
+ // This was <strong>, namespace prefix was missing.
+ CPPUNIT_ASSERT(aStream.indexOf("<reqif-xhtml:strong>") != -1);
+
+ // This was "<strike>" instead of CSS.
+ CPPUNIT_ASSERT(aStream.indexOf("<reqif-xhtml:span style=\"text-decoration: line-through\"")
+ != -1);
+
+ // This was "<font>" instead of CSS + namespace prefix was missing.
+ CPPUNIT_ASSERT(aStream.indexOf("<reqif-xhtml:span style=\"color: #ce181e\"") != -1);
+
+ // This was '<reqif-xhtml:a id="...">': non-unique bookmark name in reqif fragment.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-1), aStream.indexOf("<reqif-xhtml:a id="));
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testReqIfOleData)
+{
+ auto verify = [this]() {
+ uno::Reference<text::XTextEmbeddedObjectsSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xObjects(xSupplier->getEmbeddedObjects(),
+ uno::UNO_QUERY);
+ // This was 0, <object> without URL was ignored.
+ // Then this was 0 on export, as data of OLE nodes was ignored.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), xObjects->getCount());
+ };
+ setImportFilterOptions("xhtmlns=reqif-xhtml");
+ setImportFilterName("HTML (StarWriter)");
+ createSwDoc("reqif-ole-data.xhtml");
+ verify();
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ saveAndReload("HTML (StarWriter)");
+ verify();
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testReqIfOleImg)
+{
+ auto verify = [this]() {
+ uno::Reference<text::XTextEmbeddedObjectsSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xObjects(xSupplier->getEmbeddedObjects(),
+ uno::UNO_QUERY);
+ uno::Reference<document::XEmbeddedObjectSupplier2> xObject(xObjects->getByIndex(0),
+ uno::UNO_QUERY);
+ // This failed, OLE object had no replacement image.
+ // And then it also failed when the export lost the replacement image.
+ uno::Reference<graphic::XGraphic> xGraphic = xObject->getReplacementGraphic();
+ // This failed when query and fragment of file:// URLs were not ignored.
+ CPPUNIT_ASSERT(xGraphic.is());
+
+ uno::Reference<drawing::XShape> xShape(xObject, uno::UNO_QUERY);
+ OutputDevice* pDevice = Application::GetDefaultDevice();
+ Size aPixel(64, 64);
+ // Expected to be 1693.
+ Size aLogic(pDevice->PixelToLogic(aPixel, MapMode(MapUnit::Map100thMM)));
+ awt::Size aSize = xShape->getSize();
+ // This was only 1247, size was not set explicitly.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(aLogic.getWidth()), aSize.Width);
+
+ // Check mime/media types.
+ CPPUNIT_ASSERT_EQUAL(OUString("image/png"), getProperty<OUString>(xGraphic, "MimeType"));
+
+ uno::Reference<beans::XPropertySet> xObjectProps(xObject, uno::UNO_QUERY);
+ uno::Reference<io::XActiveDataStreamer> xStreamProvider(
+ xObjectProps->getPropertyValue("EmbeddedObject"), uno::UNO_QUERY);
+ uno::Reference<io::XSeekable> xStream(xStreamProvider->getStream(), uno::UNO_QUERY);
+ // This was empty when either import or export handling was missing.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int64>(37888), xStream->getLength());
+
+ // Check alternate text (it was empty, for export the 'alt' attribute was used).
+ CPPUNIT_ASSERT_EQUAL(OUString("OLE Object"),
+ getProperty<OUString>(xObject, "Title").trim());
+
+ if (!isExported())
+ return;
+
+ // "type" attribute was missing for the inner <object> element.
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ CPPUNIT_ASSERT(aStream.indexOf("type=\"image/png\"") != -1);
+ };
+ setImportFilterOptions("xhtmlns=reqif-xhtml");
+ setImportFilterName("HTML (StarWriter)");
+ createSwDoc("reqif-ole-img.xhtml");
+ verify();
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ saveAndReload("HTML (StarWriter)");
+ verify();
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIfPngImg)
+{
+ auto verify = [this](bool bExported) {
+ uno::Reference<container::XNamed> xShape(getShape(1), uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xShape.is());
+
+ if (!bExported)
+ {
+ // Imported PNG image is not an object.
+ CPPUNIT_ASSERT_EQUAL(OUString("Image1"), xShape->getName());
+ return;
+ }
+
+ // All images are exported as objects in ReqIF mode.
+ CPPUNIT_ASSERT_EQUAL(OUString("Object1"), xShape->getName());
+
+ // This was <img>, not <object>, which is not valid in the reqif-xhtml
+ // subset.
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ CPPUNIT_ASSERT(aStream.indexOf("<reqif-xhtml:object") != -1);
+
+ // Make sure that both RTF and PNG versions are written.
+ CPPUNIT_ASSERT(aStream.indexOf("text/rtf") != -1);
+ // This failed when images with a query in their file:// URL failed to
+ // import.
+ CPPUNIT_ASSERT(aStream.indexOf("image/png") != -1);
+ };
+
+ ImportFromReqif(createFileURL(u"reqif-png-img.xhtml"));
+ verify(/*bExported=*/false);
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ comphelper::makePropertyValue("ExportImagesAsOLE", true),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+ mxComponent->dispose();
+ ImportFromReqif(maTempFile.GetURL());
+ verify(/*bExported=*/true);
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testReqIfJpgImg)
+{
+ setImportFilterOptions("xhtmlns=reqif-xhtml");
+ setImportFilterName("HTML (StarWriter)");
+ createSwDoc("reqif-jpg-img.xhtml");
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ save(mpFilter);
+
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ // This was image/jpeg, JPG was not converted to PNG in ReqIF mode.
+ CPPUNIT_ASSERT(aStream.indexOf("type=\"image/png\"") != -1);
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testReqIfTable)
+{
+ setImportFilterOptions("xhtmlns=reqif-xhtml");
+ setImportFilterName("HTML (StarWriter)");
+ createSwDoc("reqif-table.xhtml");
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ save(mpFilter);
+
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // <div> was missing, so the XHTML fragment wasn't a valid
+ // xhtml.BlkStruct.class type anymore.
+ assertXPath(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr/reqif-xhtml:th"_ostr,
+ 1);
+ // Make sure that the cell background is not written using CSS.
+ assertXPathNoAttribute(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr/reqif-xhtml:th"_ostr,
+ "style"_ostr);
+ // The attribute was present, which is not valid in reqif-xhtml.
+ assertXPathNoAttribute(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr/reqif-xhtml:th"_ostr,
+ "bgcolor"_ostr);
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testReqIfTable2)
+{
+ createSwDoc("reqif-table2.odt");
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ save(mpFilter);
+
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ // This failed, <reqif-xhtml:td width="..."> was written.
+ CPPUNIT_ASSERT(aStream.indexOf("<reqif-xhtml:td>") != -1);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIfTableHeight)
+{
+ // Given a document with a table in it, with an explicit row height:
+ createSwDoc();
+ uno::Sequence<beans::PropertyValue> aTableProperties = {
+ comphelper::makePropertyValue("Rows", static_cast<sal_Int32>(1)),
+ comphelper::makePropertyValue("Columns", static_cast<sal_Int32>(1)),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertTable", aTableProperties);
+ uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
+ uno::UNO_QUERY);
+ uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xRow(xTable->getRows()->getByIndex(0), uno::UNO_QUERY);
+ xRow->setPropertyValue("Height", uno::Any(static_cast<sal_Int32>(1000)));
+
+ // When exporting to reqif-xhtml:
+ ExportToReqif();
+
+ // Then make sure that the explicit cell height is omitted from the output:
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed, explicit height was
+ // written, which is not valid reqif-xhtml.
+ assertXPathNoAttribute(pDoc, "//reqif-xhtml:td"_ostr, "height"_ostr);
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testXHTMLUseCSS)
+{
+ createSwDoc("xhtml-css.odt");
+ setFilterOptions("XHTML");
+ save(mpFilter);
+
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ // This failed, <font face="..."> was written.
+ CPPUNIT_ASSERT(aStream.indexOf("<span style=\"font-family:") != -1);
+ // This failed, <font size="..."> was written.
+ CPPUNIT_ASSERT(aStream.indexOf("<span style=\"font-size:") != -1);
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testReqIfList)
+{
+ setImportFilterOptions("xhtmlns=reqif-xhtml");
+ setImportFilterName("HTML (StarWriter)");
+ createSwDoc("reqif-list.xhtml");
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ save(mpFilter);
+
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ // This failed, <ul> was written.
+ CPPUNIT_ASSERT(aStream.indexOf("<reqif-xhtml:ul>") != -1);
+
+ // This failed, the 'style' attribute was written, even if the input did
+ // not had one.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-1), aStream.indexOf(" style=\""));
+
+ // This failed <li> was only opened, not closed.
+ CPPUNIT_ASSERT(aStream.indexOf("</reqif-xhtml:li>") != -1);
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testReqIfOle2)
+{
+ auto verify = [this]() {
+ uno::Reference<text::XTextEmbeddedObjectsSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xObjects(xSupplier->getEmbeddedObjects(),
+ uno::UNO_QUERY);
+ uno::Reference<document::XEmbeddedObjectSupplier2> xObject(xObjects->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<io::XActiveDataStreamer> xEmbeddedObject(
+ xObject->getExtendedControlOverEmbeddedObject(), uno::UNO_QUERY);
+ // This failed, the "RTF fragment" native data was loaded as-is, we had no
+ // filter to handle it, so nothing happened on double-click.
+ CPPUNIT_ASSERT(xEmbeddedObject.is());
+ uno::Reference<io::XSeekable> xStream(xEmbeddedObject->getStream(), uno::UNO_QUERY);
+ // This was 38375, msfilter::rtfutil::ExtractOLE2FromObjdata() wrote
+ // everything after the OLE1 header into the OLE2 stream, while the
+ // Presentation field after the OLE2 data doesn't belong there.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int64>(37888), xStream->getLength());
+ // Finally the export also failed as it tried to open the stream from the
+ // document storage, but the embedded object already opened it, so an
+ // exception of type com.sun.star.io.IOException was thrown.
+
+ if (isExported())
+ {
+ // Check that the replacement graphic is exported at RTF level.
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+ // Get the path of the RTF data.
+ OUString aOlePath = getXPath(
+ pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object"_ostr,
+ "data"_ostr);
+ OUString aOleSuffix(".ole");
+ CPPUNIT_ASSERT(aOlePath.endsWith(aOleSuffix));
+ INetURLObject aUrl(maTempFile.GetURL());
+ aUrl.setBase(aOlePath.subView(0, aOlePath.getLength() - aOleSuffix.getLength()));
+ aUrl.setExtension(u"ole");
+ OUString aOleUrl = aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+
+ // Search for \result in the RTF data.
+ SvFileStream aOleStream(aOleUrl, StreamMode::READ);
+ CPPUNIT_ASSERT(aOleStream.IsOpen());
+ OString aOleString(read_uInt8s_ToOString(aOleStream, aOleStream.TellEnd()));
+ // Without the accompanying fix in place, this test would have failed,
+ // replacement graphic was missing at RTF level.
+ CPPUNIT_ASSERT(aOleString.indexOf(OOO_STRING_SVTOOLS_RTF_RESULT) != -1);
+ }
+ };
+ setImportFilterOptions("xhtmlns=reqif-xhtml");
+ setImportFilterName("HTML (StarWriter)");
+ createSwDoc("reqif-ole2.xhtml");
+ verify();
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ saveAndReload(mpFilter);
+ verify();
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testReqIfOle2Odg)
+{
+ auto verify = [this]() {
+ uno::Reference<text::XTextEmbeddedObjectsSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xObjects(xSupplier->getEmbeddedObjects(),
+ uno::UNO_QUERY);
+ uno::Reference<document::XEmbeddedObjectSupplier> xTextEmbeddedObject(
+ xObjects->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<lang::XServiceInfo> xObject(xTextEmbeddedObject->getEmbeddedObject(),
+ uno::UNO_QUERY);
+ // This failed, both import and export failed to handle OLE2 that contains
+ // just ODF.
+ CPPUNIT_ASSERT(xObject.is());
+ CPPUNIT_ASSERT(xObject->supportsService("com.sun.star.drawing.DrawingDocument"));
+ };
+ setImportFilterOptions("xhtmlns=reqif-xhtml");
+ setImportFilterName("HTML (StarWriter)");
+ createSwDoc("reqif-ole-odg.xhtml");
+ verify();
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ saveAndReload(mpFilter);
+ verify();
+}
+
+DECLARE_HTMLEXPORT_TEST(testList, "list.html")
+{
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ // This failed, it was <li/>, i.e. list item was closed before content
+ // started.
+ CPPUNIT_ASSERT(aStream.indexOf("<li>") != -1);
+}
+
+DECLARE_HTMLEXPORT_TEST(testTransparentImage, "transparent-image.odt")
+{
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ OUString aSource = getXPath(pDoc, "/html/body/p/img"_ostr, "src"_ostr);
+ OUString aMessage = "src attribute is: " + aSource;
+ // This was a jpeg, transparency was lost.
+ CPPUNIT_ASSERT_MESSAGE(aMessage.toUtf8().getStr(), aSource.endsWith(".gif"));
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTransparentImageReqIf)
+{
+ createSwDoc("transparent-image.odt");
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ comphelper::makePropertyValue("ExportImagesAsOLE", true),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ OUString aSource = getXPath(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object/reqif-xhtml:object"_ostr,
+ "data"_ostr);
+ OUString aMessage = "src attribute is: " + aSource;
+ // This was GIF, when the intention was to force PNG.
+ CPPUNIT_ASSERT_MESSAGE(aMessage.toUtf8().getStr(), aSource.endsWith(".png"));
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testOleNodataReqIf)
+{
+ createSwDoc("reqif-ole-nodata.odt");
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ save(mpFilter);
+
+ // This failed, io::IOException was thrown during the filter() call.
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // Make sure the native <object> element has the required data attribute.
+ OUString aSource = getXPath(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object/reqif-xhtml:object"_ostr,
+ "data"_ostr);
+ CPPUNIT_ASSERT(!aSource.isEmpty());
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testNoLangReqIf)
+{
+ createSwDoc("reqif-no-lang.odt");
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ save(mpFilter);
+
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // Make sure that xml:lang is not written in ReqIF mode.
+ assertXPathNoAttribute(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:h1"_ostr,
+ "lang"_ostr);
+}
+
+DECLARE_HTMLEXPORT_TEST(testFieldShade, "field-shade.odt")
+{
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ // Without the accompanying fix in place, this test would have failed with 'Expected: 1; Actual:
+ // 0', i.e. shading for the field was lost.
+ assertXPath(pDoc, "/html/body/p[1]/span"_ostr, "style"_ostr, "background: #c0c0c0");
+
+ // Check that field shading is written only in case there is no user-defined span background.
+ assertXPath(pDoc, "/html/body/p[2]/span"_ostr, "style"_ostr, "background: #ff0000");
+ // Without the accompanying fix in place, this test would have failed with 'Expected: 0; Actual:
+ // 1', i.e there was an inner span hiding the wanted background color.
+ assertXPath(pDoc, "/html/body/p[2]/span/span"_ostr, 0);
+}
+
+DECLARE_HTMLEXPORT_TEST(testTdf132739, "tdf132739.odt")
+{
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ // Without the fix in place, this test would have failed with
+ // - Expected: background: #5983b0; border: 1px solid #333333; padding: 0.04in
+ // - Actual : background: #5983b0
+ assertXPath(pDoc, "/html/body/table/tr[1]/td"_ostr, "style"_ostr,
+ "background: #5983b0; border: 1px solid #333333; padding: 0.04in");
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testFieldShadeReqIf)
+{
+ createSwDoc("field-shade-reqif.odt");
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ save(mpFilter);
+
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 0
+ // - Actual : 2
+ // i.e. the ReqIF subset of xhtml had a background color and a page number field, resulting in
+ // an invalid ReqIF-XHTML.
+ assertXPath(pDoc, "/html/body/div/p[1]/span"_ostr, 0);
+ assertXPath(pDoc, "/html/body/div/p[1]/sdfield"_ostr, 0);
+}
+
+DECLARE_HTMLEXPORT_TEST(testTdf126879, "tdf126879.odt")
+{
+ constexpr OString aExpected("<!DOCTYPE html>"_ostr);
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ const OString aActual(read_uInt8s_ToOString(*pStream, aExpected.getLength()));
+ // Without the fix in place, this test would have failed with
+ // - Expected: <!DOCTYPE html>
+ // - Actual : <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+ CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testBlockQuoteReqIf)
+{
+ // Build a document model that uses the Quotations paragraph style.
+ createSwDoc();
+ uno::Reference<beans::XPropertySet> xParagraph(getParagraph(1), uno::UNO_QUERY);
+ xParagraph->setPropertyValue("ParaStyleName", uno::Any(OUString("Quotations")));
+
+ // Export it.
+ setFilterOptions("xhtmlns=reqif-xhtml");
+ save("HTML (StarWriter)");
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. <blackquote> had character (direct) children, which is invalid xhtml.
+ assertXPath(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:blockquote/reqif-xhtml:p"_ostr,
+ 1);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testRTFOLEMimeType)
+{
+ // Import a document with an embedded object.
+ OUString aType("test/rtf");
+ ImportFromReqif(createFileURL(u"reqif-ole-data.xhtml"));
+
+ // Export it.
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ comphelper::makePropertyValue("RTFOLEMimeType", aType),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: test/rtf
+ // - Actual : text/rtf
+ // i.e. the MIME type was always text/rtf, not taking the store parameter into account.
+ assertXPath(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object"_ostr,
+ "type"_ostr, aType);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testChinese)
+{
+ // Load a document with Chinese text in it.
+ createSwDoc("reqif-chinese.odt");
+
+ // Export it.
+ ExportToReqif();
+ // Without the accompanying fix in place, this would have failed as the output was not
+ // well-formed.
+ WrapReqifFromTempFile();
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifComment)
+{
+ // Create a document with a comment in it.
+ createSwDoc();
+ uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence({
+ { "Text", uno::Any(OUString("some text")) },
+ { "Author", uno::Any(OUString("me")) },
+ });
+ dispatchCommand(mxComponent, ".uno:InsertAnnotation", aPropertyValues);
+
+ // Export it.
+ ExportToReqif();
+ // Without the accompanying fix in place, this would have failed as the output was not
+ // well-formed.
+ WrapReqifFromTempFile();
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifFontNameSize)
+{
+ // Create a document with a custom font name and size in it.
+ createSwDoc();
+ uno::Reference<beans::XPropertySet> xParagraph(getParagraph(1), uno::UNO_QUERY);
+ xParagraph->setPropertyValue("CharFontName", uno::Any(OUString("Liberation Serif")));
+ float fCharHeight = 14.0;
+ xParagraph->setPropertyValue("CharHeight", uno::Any(fCharHeight));
+ sal_Int32 nCharColor = 0xff0000;
+ xParagraph->setPropertyValue("CharColor", uno::Any(nCharColor));
+ uno::Reference<text::XTextRange> xTextRange(xParagraph, uno::UNO_QUERY);
+ xTextRange->setString("x");
+
+ // Export it.
+ ExportToReqif();
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 3
+ // i.e. font name and size was written, even if that's not relevant for ReqIF.
+ assertXPath(pDoc, "//reqif-xhtml:span"_ostr, 1);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifParagraphAlignment)
+{
+ // Create a document with an explicitly aligned paragraph.
+ createSwDoc();
+ uno::Reference<beans::XPropertySet> xParagraph(getParagraph(1), uno::UNO_QUERY);
+ xParagraph->setPropertyValue("ParaAdjust",
+ uno::Any(static_cast<sal_Int16>(style::ParagraphAdjust_RIGHT)));
+
+ // Export it.
+ ExportToReqif();
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected:
+ // - Actual : right
+ // i.e. the <reqif-xhtml:p align="..."> markup was used, which is invalid.
+ assertXPathNoAttribute(pDoc, "//reqif-xhtml:p"_ostr, "align"_ostr);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1PDF)
+{
+ // Save to reqif-xhtml.
+ createSwDoc("pdf-ole.odt");
+
+ ExportToReqif();
+ OUString aRtfUrl = GetOlePath();
+ SvMemoryStream aOle1;
+ ParseOle1FromRtfUrl(aRtfUrl, aOle1);
+
+ // Check the content of the ole1 data.
+ OLE1Reader aOle1Reader(aOle1);
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 39405
+ // - Actual : 43008
+ // i.e. we did not work with the Ole10Native stream, rather created an OLE1 wrapper around the
+ // OLE1-in-OLE2 data, resulting in additional size.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0x99ed), aOle1Reader.m_nNativeDataSize);
+
+ // Now import this back and check the ODT result.
+ mxComponent->dispose();
+ mxComponent.clear();
+ ImportFromReqif(maTempFile.GetURL());
+ save("writer8");
+ uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
+ = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory),
+ maTempFile.GetURL());
+ uno::Reference<io::XInputStream> xInputStream(xNameAccess->getByName("Object 2"),
+ uno::UNO_QUERY);
+ std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
+ tools::SvRef<SotStorage> pStorage = new SotStorage(*pStream);
+ tools::SvRef<SotStorageStream> pOleNative = pStorage->OpenSotStream("\1Ole10Native");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 39409
+ // - Actual : 0
+ // i.e. we didn't handle the case when the ole1 payload was not an ole2 container. Note how the
+ // expected value is the same as nData above + 4 bytes, since this data is length-prefixed.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(39409), pOleNative->GetSize());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1Paint)
+{
+ // Load the bug document, which has OLE1 data in it, which is not a wrapper around OLE2 data.
+ ImportFromReqif(createFileURL(u"paint-ole.xhtml"));
+
+ // Save it as ODT to inspect the result of the OLE1 -> OLE2 conversion.
+ save("writer8");
+ uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
+ = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory),
+ maTempFile.GetURL());
+ uno::Reference<io::XInputStream> xInputStream(xNameAccess->getByName("Object 2"),
+ uno::UNO_QUERY);
+ std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
+ tools::SvRef<SotStorage> pStorage = new SotStorage(*pStream);
+ // Check the clsid of the root stream of the OLE2 storage.
+ SvGlobalName aActual = pStorage->GetClassName();
+ SvGlobalName aExpected(0x0003000A, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46);
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 0003000A-0000-0000-c000-000000000046
+ // - Actual : 0003000C-0000-0000-c000-000000000046
+ // i.e. the "Package" clsid was used on the OLE2 storage unconditionally, even for an mspaint
+ // case, which has its own clsid.
+ CPPUNIT_ASSERT_EQUAL(aExpected.GetHexName(), aActual.GetHexName());
+
+ ExportToReqif();
+ OUString aRtfUrl = GetOlePath();
+ SvMemoryStream aOle1;
+ ParseOle1FromRtfUrl(aRtfUrl, aOle1);
+
+ // Check the content of the ole1 data.
+ // Skip ObjectHeader, see [MS-OLEDS] 2.2.4.
+ aOle1.Seek(0);
+ sal_uInt32 nData;
+ aOle1.ReadUInt32(nData); // OLEVersion
+ aOle1.ReadUInt32(nData); // FormatID
+ aOle1.ReadUInt32(nData); // ClassName
+ CPPUNIT_ASSERT(nData);
+ OString aClassName = read_uInt8s_ToOString(aOle1, nData - 1);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: PBrush
+ // - Actual : Package
+ // i.e. a hardcoded class name was written.
+ CPPUNIT_ASSERT_EQUAL("PBrush"_ostr, aClassName);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1PaintBitmapFormat)
+{
+ // Given a document with a 8bpp bitmap:
+ createSwDoc("paint-ole-bitmap-format.odt");
+
+ // When exporting to reqif-xhtml with ExportImagesAsOLE enabled:
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ comphelper::makePropertyValue("ExportImagesAsOLE", true),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ // Then make sure the resulting bitmap is 24bpp:
+ OUString aRtfUrl = GetOlePath();
+ SvMemoryStream aOle1;
+ ParseOle1FromRtfUrl(aRtfUrl, aOle1);
+ OLE1Reader aOle1Reader(aOle1);
+ Bitmap aBitmap;
+ SvMemoryStream aMemory;
+ aMemory.WriteBytes(aOle1Reader.m_aNativeData.data(), aOle1Reader.m_aNativeData.size());
+ aMemory.Seek(0);
+ CPPUNIT_ASSERT(ReadDIB(aBitmap, aMemory, true));
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 24
+ // - Actual : 8
+ // i.e. it was not a pixel format ms paint could handle in OLE mode.
+ CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N24_BPP, aBitmap.getPixelFormat());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testMultiParaListItem)
+{
+ // Create a document with 3 list items: A, B&C and D.
+ createSwDoc();
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("A");
+ SwDoc* pDoc = pWrtShell->GetDoc();
+ {
+ // Enable numbering.
+ sal_uInt16 nPos = pDoc->MakeNumRule(pDoc->GetUniqueNumRuleName());
+ SwNumRule* pNumRule = pDoc->GetNumRuleTable()[nPos];
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ }
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("B");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("C");
+ {
+ // C is in the same list item as B.
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetCountedInList(false);
+ }
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("D");
+
+ ExportToReqif();
+
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ assertXPathContent(pXmlDoc, "//reqif-xhtml:ol/reqif-xhtml:li[1]/reqif-xhtml:p"_ostr, "A");
+ assertXPathContent(pXmlDoc, "//reqif-xhtml:ol/reqif-xhtml:li[2]/reqif-xhtml:p[1]"_ostr, "B");
+ // Without the accompanying fix in place, this test would have failed with:
+ // XPath '//reqif-xhtml:ol/reqif-xhtml:li[2]/reqif-xhtml:p[2]' not found
+ // i.e. </li> was written before "C", not after "C", so "C" was not in the 2nd list item.
+ assertXPathContent(pXmlDoc, "//reqif-xhtml:ol/reqif-xhtml:li[2]/reqif-xhtml:p[2]"_ostr, "C");
+ assertXPathContent(pXmlDoc, "//reqif-xhtml:ol/reqif-xhtml:li[3]/reqif-xhtml:p"_ostr, "D");
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testUnderlineNone)
+{
+ // Create a document with a single paragraph: its underlying is set to an explicit 'none' value.
+ createSwDoc();
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ xText->insertString(xText->getEnd(), "x", /*bAbsorb=*/false);
+ uno::Reference<beans::XPropertySet> xParagraph(getParagraph(1), uno::UNO_QUERY);
+ xParagraph->setPropertyValue("CharUnderline", uno::Any(sal_Int16(awt::FontUnderline::NONE)));
+
+ // Export to reqif-xhtml.
+ ExportToReqif();
+
+ // Make sure that the paragraph has no explicit style, because "text-decoration: none" is
+ // filtered out.
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ assertXPathNoAttribute(pXmlDoc, "//reqif-xhtml:div/reqif-xhtml:p"_ostr, "style"_ostr);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1PresDataNoOle2)
+{
+ // Save to reqif-xhtml.
+ createSwDoc("no-ole2-pres-data.odt");
+ ExportToReqif();
+ OUString aRtfUrl = GetOlePath();
+ SvMemoryStream aOle1;
+ ParseOle1FromRtfUrl(aRtfUrl, aOle1);
+
+ // Check the content of the ole1 data.
+ // Without the accompanying fix in place, this test would have failed as there was no
+ // presentation data after the native data in the OLE1 container. The result was not editable in
+ // Word.
+ OLE1Reader aOle1Reader(aOle1);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1PresDataWmfOnly)
+{
+ // Save to reqif-xhtml.
+ createSwDoc("ole1-pres-data-wmf.odt");
+ ExportToReqif();
+ OUString aRtfUrl = GetOlePath();
+ SvMemoryStream aOle1;
+ ParseOle1FromRtfUrl(aRtfUrl, aOle1);
+
+ OLE1Reader aOle1Reader(aOle1);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 135660
+ // - Actual : 272376
+ // i.e. we wrote some additional EMF data into the WMF output, which broke Word.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(135660), aOle1Reader.m_nPresentationDataSize);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifAscharObjsize)
+{
+ // Given a document with an as-char anchored embedded object:
+ createSwDoc("reqif-aschar-objsize.odt");
+
+ // When exporting to reqif-xhtml:
+ ExportToReqif();
+
+ // Then make sure that the RTF snippet has the correct aspect ratio:
+ OUString aRtfUrl = GetOlePath();
+ SvMemoryStream aRtf;
+ HtmlExportTest::wrapRtfFragment(aRtfUrl, aRtf);
+ tools::SvRef<TestReqIfRtfReader> xReader(new TestReqIfRtfReader(aRtf));
+ CPPUNIT_ASSERT(xReader->CallParser() != SvParserState::Error);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 7344
+ // - Actual : 2836
+ // i.e. the aspect ratio was 1:1, while the PNG aspect ratio was correctly not 1:1.
+ CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(7344), xReader->GetObjw());
+ CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(4116), xReader->GetObjh());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifObjdataPresentationDataSize)
+{
+ // Given a document with an OLE2 embedded object, containing a preview:
+ createSwDoc("reqif-objdata-presentationdatasize.odt");
+
+ // When exporting to ReqIF:
+ ExportToReqif();
+
+ // Then make sure that the PresentationDataSize in the RTF's objdata blob is correct:
+ OUString aRtfUrl = GetOlePath();
+ SvMemoryStream aOle1;
+ ParseOle1FromRtfUrl(aRtfUrl, aOle1);
+ OLE1Reader aOle1Reader(aOle1);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 565994
+ // - Actual : 330240 (Linux)
+ // - Actual : 566034 (Windows, when Word is installed)
+ // because PresentationData was taken from the OLE2 stream but its size was taken from RTF.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(565994), aOle1Reader.m_nPresentationDataSize);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testListHeading)
+{
+ // Given a document with a list heading:
+ createSwDoc();
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("list header");
+ SwDoc* pDoc = pWrtShell->GetDoc();
+ sal_uInt16 nPos = pDoc->MakeNumRule(pDoc->GetUniqueNumRuleName());
+ SwNumRule* pNumRule = pDoc->GetNumRuleTable()[nPos];
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ rTextNode.SetCountedInList(false);
+
+ // When exporting to ReqIF:
+ ExportToReqif();
+
+ // Then make sure the output is valid xhtml:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+
+ // Without the accompanying fix in place, this test would have failed:
+ // - expected: <div><ol><li style="display: block"><p>...</p></li></ol></div>
+ // - actual : <div><ol><p>...</p></li></ol></div>
+ // because a </li> but no <li> is not well-formed and <ol> with a non-li children is invalid.
+ OUString aContent
+ = getXPathContent(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ol/"
+ "reqif-xhtml:li[@style='display: block']/reqif-xhtml:p"_ostr);
+ CPPUNIT_ASSERT_EQUAL(OUString("list header"), aContent.trim());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testPartiallyNumberedList)
+{
+ // Given a document with a list, first para is numbered, second is not:
+ createSwDoc();
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("list header");
+ SwDoc* pDoc = pWrtShell->GetDoc();
+ sal_uInt16 nPos = pDoc->MakeNumRule(pDoc->GetUniqueNumRuleName());
+ SwNumRule* pNumRule = pDoc->GetNumRuleTable()[nPos];
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ }
+ pWrtShell->Insert2("numbered");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert2("not numbered");
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ rTextNode.SetCountedInList(false);
+ }
+
+ // When exporting to ReqIF:
+ ExportToReqif();
+
+ // Then make sure the output is well-formed xhtml:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed:
+ // - expected: <li><p>...</p><p>...</p></li>
+ // - actual : <li><p>...</p><p>...</p>
+ // because a <li> without a matching </li> is not well-formed, and the </li> was omitted because
+ // the second para was not numbered.
+ assertXPath(
+ pXmlDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ol/reqif-xhtml:li/reqif-xhtml:p"_ostr, 2);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testPartiallyNumberedListHTML)
+{
+ // Given a document with a list, first para is numbered, second is not:
+ createSwDoc();
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("list header");
+ SwDoc* pDoc = pWrtShell->GetDoc();
+ sal_uInt16 nPos = pDoc->MakeNumRule(pDoc->GetUniqueNumRuleName());
+ SwNumRule* pNumRule = pDoc->GetNumRuleTable()[nPos];
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->nNode.GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ }
+ pWrtShell->Insert2("numbered");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert2("not numbered");
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->nNode.GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ rTextNode.SetCountedInList(false);
+ }
+
+ // When exporting to HTML:
+ ExportToHTML();
+
+ SvMemoryStream aStream;
+ WrapFromTempFile(aStream);
+ xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream);
+ CPPUNIT_ASSERT(pXmlDoc); // if we have missing closing marks - parse error
+
+ // Without the accompanying fix in place, this test would have failed:
+ // - expected: <li><p>...</p><p>...</p></li>
+ // - actual : <li><p>...</p><p>...</p>
+ // because a <li> without a matching </li> is not well-formed, and the </li> was omitted because
+ // the second para was not numbered.
+
+ assertXPath(pXmlDoc, "/html/body/ol/li/p"_ostr, 2);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testListHeaderAndItem)
+{
+ // Given a document with a list, first para is not numbered, but the second is:
+ createSwDoc();
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("not numbered");
+ SwDoc* pDoc = pWrtShell->GetDoc();
+ sal_uInt16 nPos = pDoc->MakeNumRule(pDoc->GetUniqueNumRuleName());
+ SwNumRule* pNumRule = pDoc->GetNumRuleTable()[nPos];
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ rTextNode.SetCountedInList(false);
+ }
+ pWrtShell->SplitNode();
+ pWrtShell->Insert2("numbered");
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ }
+
+ // When exporting to ReqIF:
+ ExportToReqif();
+
+ // Then make sure the output is well-formed xhtml:
+ // Without the accompanying fix in place, this would have failed:
+ // Entity: line 3: parser error : Opening and ending tag mismatch: ol line 3 and li
+ // <reqif-xhtml:ol><reqif-xhtml:p>not numbered</reqif-xhtml:p></reqif-xhtml:li>
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Make sure that in case the list has a header and an item, then both are wrapped in an <li>
+ // element.
+ assertXPath(
+ pXmlDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ol/reqif-xhtml:li/reqif-xhtml:p"_ostr, 2);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testBlockQuoteNoMargin)
+{
+ // Given a document with some text, para style set to Quotations, no bottom margin:
+ createSwDoc();
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ xText->insertString(xText->getEnd(), "string", /*bAbsorb=*/false);
+ uno::Reference<beans::XPropertySet> xQuotations(
+ getStyles("ParagraphStyles")->getByName("Quotations"), uno::UNO_QUERY);
+ xQuotations->setPropertyValue("ParaBottomMargin", uno::Any(static_cast<sal_Int32>(0)));
+ uno::Reference<beans::XPropertySet> xParagraph(getParagraph(1), uno::UNO_QUERY);
+ xParagraph->setPropertyValue("ParaStyleName", uno::Any(OUString("Quotations")));
+
+ // When exporting to XHTML:
+ ExportToReqif();
+
+ // Then make sure the output is valid xhtml:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed:
+ // - expected: <blockquote><p>...</p></blockquote>
+ // - actual : <blockquote>...</blockquote>
+ // i.e. <blockquote> is can't have character children, but it had.
+ assertXPathContent(
+ pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:blockquote/reqif-xhtml:p"_ostr,
+ "string");
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifImageToOle)
+{
+ // Given a document with an image:
+ createSwDoc();
+ uno::Sequence<beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FileName", createFileURL(u"ole2.png")),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertGraphic", aArgs);
+
+ // When exporting to XHTML:
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ comphelper::makePropertyValue("ExportImagesAsOLE", true),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ // Then make sure we export that PNG as WMF in ReqIF mode:
+ OUString aRtfUrl = GetOlePath();
+ SvMemoryStream aRtf;
+ HtmlExportTest::wrapRtfFragment(aRtfUrl, aRtf);
+ tools::SvRef<TestReqIfRtfReader> xReader(new TestReqIfRtfReader(aRtf));
+ CPPUNIT_ASSERT(xReader->CallParser() != SvParserState::Error);
+ // Without the accompanying fix in place, this test would have failed:
+ // - Expected: 8
+ // - Actual : 0
+ // i.e. the image was exported as PNG, not as WMF (with a version).
+ CPPUNIT_ASSERT_EQUAL(8, xReader->getWmetafile());
+
+ // Make sure that the native data byte array is not empty.
+ SvMemoryStream aOle1;
+ CPPUNIT_ASSERT(xReader->WriteObjectData(aOle1));
+ // Without the accompanying fix in place, this test would have failed, as aOle1 was empty.
+ OLE1Reader aOle1Reader(aOle1);
+ CPPUNIT_ASSERT(aOle1Reader.m_nNativeDataSize);
+
+ // Make sure that the presentation data byte array is not empty.
+ // Without the accompanying fix in place, this test would have failed, as aOle1 only contained
+ // the native data.
+ CPPUNIT_ASSERT(aOle1Reader.m_nPresentationDataSize);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifEmbedPNGDirectly)
+{
+ // Given a document with an image:
+ createSwDoc();
+ uno::Sequence<beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FileName", createFileURL(u"ole2.png")),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertGraphic", aArgs);
+
+ // When exporting to XHTML:
+ ExportToReqif();
+
+ // Then make sure the PNG is embedded directly, without an RTF wrapper:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: image/png
+ // - Actual : text/rtf
+ // i.e. even PNG was wrapped in an RTF.
+ assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object"_ostr, "type"_ostr, "image/png");
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifEmbedJPGDirectly)
+{
+ // Given a document with an image:
+ createSwDoc();
+ uno::Sequence<beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FileName", createFileURL(u"reqif-ole-img.jpg")),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertGraphic", aArgs);
+
+ // When exporting to XHTML:
+ ExportToReqif();
+
+ // Then make sure the JPG is embedded directly, without an RTF wrapper:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object"_ostr, "type"_ostr, "image/jpeg");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: image/jpeg
+ // - Actual : image/png
+ // i.e. first the original JPG data was lost, then the inner PNG fallback was missing.
+ assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object/reqif-xhtml:object"_ostr, "type"_ostr,
+ "image/png");
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifEmbedPNGShapeDirectly)
+{
+ // Given a document with an image shape:
+ createSwDoc();
+ uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"), uno::UNO_QUERY);
+ xShape->setSize(awt::Size(10000, 10000));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ xShapeProps->setPropertyValue("GraphicURL", uno::Any(createFileURL(u"ole2.png")));
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
+ xDrawPageSupplier->getDrawPage()->add(xShape);
+
+ // When exporting to XHTML:
+ ExportToReqif();
+
+ // Then make sure the PNG is embedded directly, without an RTF wrapper:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - no attribute 'type' exist
+ // i.e. the PNG was exported as GIF, without an explicit type.
+ assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object"_ostr, "type"_ostr, "image/png");
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifEmbedJPGShapeDirectly)
+{
+ // Given a document with an image:
+ createSwDoc();
+ uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"), uno::UNO_QUERY);
+ xShape->setSize(awt::Size(10000, 10000));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ xShapeProps->setPropertyValue("GraphicURL", uno::Any(createFileURL(u"reqif-ole-img.jpg")));
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
+ xDrawPageSupplier->getDrawPage()->add(xShape);
+
+ // When exporting to XHTML:
+ ExportToReqif();
+
+ // Then make sure the JPG is embedded directly, without an RTF wrapper:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: image/jpeg
+ // - Actual : image/png
+ // i.e. first the original JPG data was lost, then the inner PNG fallback was missing.
+ assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object"_ostr, "type"_ostr, "image/jpeg");
+ assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object/reqif-xhtml:object"_ostr, "type"_ostr,
+ "image/png");
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifEmbedPNGShapeAsOLE)
+{
+ // Given a document with an image shape:
+ createSwDoc();
+ uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"), uno::UNO_QUERY);
+ xShape->setSize(awt::Size(10000, 10000));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ xShapeProps->setPropertyValue("GraphicURL", uno::Any(createFileURL(u"ole2.png")));
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
+ xDrawPageSupplier->getDrawPage()->add(xShape);
+
+ // When exporting to XHTML:
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ comphelper::makePropertyValue("ExportImagesAsOLE", true),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ // Then make sure the PNG is embedded with an RTF wrapper:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: text/rtf
+ // - Actual : image/png
+ // i.e. the OLE wrapper around the PNG was missing.
+ assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object"_ostr, "type"_ostr, "text/rtf");
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifEmbedShapeAsPNG)
+{
+ // Given a document with a shape:
+ createSwDoc();
+ uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
+ xShape->setSize(awt::Size(10000, 10000));
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
+ xDrawPageSupplier->getDrawPage()->add(xShape);
+
+ // When exporting to XHTML:
+ ExportToReqif();
+
+ // Then make sure the shape is embedded as a PNG:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: image/png
+ // - Actual : image/x-vclgraphic
+ // i.e. the result was invalid ReqIF.
+ assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object"_ostr, "type"_ostr, "image/png");
+
+ // Then check the pixel size of the shape:
+ Size aPixelSize(Application::GetDefaultDevice()->LogicToPixel(Size(10000, 10000),
+ MapMode(MapUnit::Map100thMM)));
+ // Without the accompanying fix in place, this test would have failed with:
+ // - no attribute 'width' exist
+ // i.e. shapes had no width.
+ assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object"_ostr, "width"_ostr,
+ OUString::number(aPixelSize.getWidth()));
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testShapeAsImageHtml)
+{
+ // Given a document with a shape:
+ createSwDoc();
+ uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
+ xShape->setSize(awt::Size(5080, 2540));
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
+ xDrawPageSupplier->getDrawPage()->add(xShape);
+
+ // When exporting to plain HTML:
+ saveAndReload("HTML (StarWriter)");
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected:
+ // - Actual : />
+ // i.e. the output was not well-formed.
+ CPPUNIT_ASSERT_EQUAL(OUString(" "), getParagraph(1)->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testJson)
+{
+ // Given a document with a shape:
+ createSwDoc();
+ uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
+ xShape->setSize(awt::Size(2540, 2540));
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
+ xDrawPageSupplier->getDrawPage()->add(xShape);
+
+ // When exporting to HTML, and specifying options as JSON:
+ setFilterOptions("{\"XhtmlNs\":{\"type\":\"string\", \"value\":\"reqif-xhtml\"},"
+ "\"ShapeDPI\":{\"type\":\"long\",\"value\":\"192\"}}");
+ save("HTML (StarWriter)");
+
+ // Then make sure those options are not ignored:
+ // Without the accompanying fix in place, this test would have failed, as GetPngPath() expects
+ // XML output, but xhtmlns=reqif-xhtml was ignored.
+ OUString aPngUrl = GetPngPath();
+ SvFileStream aFileStream(aPngUrl, StreamMode::READ);
+ GraphicDescriptor aDescriptor(aFileStream, nullptr);
+ aDescriptor.Detect(/*bExtendedInfo=*/true);
+ // Make sure that the increased DPI is taken into account:
+ tools::Long nExpected = 192;
+ CPPUNIT_ASSERT_EQUAL(nExpected, aDescriptor.GetSizePixel().getWidth());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifEmbedShapeAsPNGCustomDPI)
+{
+ // Given a document with a shape:
+ createSwDoc();
+ uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
+ xShape->setSize(awt::Size(5080, 2540));
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
+ xDrawPageSupplier->getDrawPage()->add(xShape);
+ sal_Int32 nDPI = 600;
+
+ // When exporting to XHTML:
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ comphelper::makePropertyValue("ShapeDPI", nDPI),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ // Then make sure the shape is embedded as a PNG:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object"_ostr, "type"_ostr, "image/png");
+
+ // Then check the pixel size of the shape:
+ Size aPixelSize(Application::GetDefaultDevice()->LogicToPixel(Size(5080, 2540),
+ MapMode(MapUnit::Map100thMM)));
+ tools::Long nPNGWidth = 1200;
+ OUString aPngUrl = GetPngPath();
+ SvFileStream aFileStream(aPngUrl, StreamMode::READ);
+ GraphicDescriptor aDescriptor(aFileStream, nullptr);
+ aDescriptor.Detect(/*bExtendedInfo=*/true);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1200
+ // - Actual : 1000
+ // i.e. first setting a double DPI didn't result in larger pixel width of the PNG, then it was
+ // limited to 1000 pixels (because the pixel limit was 500k).
+ CPPUNIT_ASSERT_EQUAL(nPNGWidth, aDescriptor.GetSizePixel().getWidth());
+
+ // Then make sure the shape's logic size (in CSS pixels) don't change:
+ assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object"_ostr, "width"_ostr,
+ OUString::number(aPixelSize.getWidth()));
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOleBmpTransparent)
+{
+ // Given a document with a transparent image:
+ createSwDoc();
+ uno::Sequence<beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FileName", createFileURL(u"transparent.png")),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertGraphic", aArgs);
+
+ // When exporting to reqif with ExportImagesAsOLE=true:
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ comphelper::makePropertyValue("ExportImagesAsOLE", true),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ // Then make sure the transparent pixel turns into white:
+ SvMemoryStream aOle1;
+ ParseOle1FromRtfUrl(GetOlePath(), aOle1);
+ OLE1Reader aOle1Reader(aOle1);
+ SvMemoryStream aBitmapStream(aOle1Reader.m_aNativeData.data(), aOle1Reader.m_aNativeData.size(),
+ StreamMode::READ);
+ Bitmap aBitmap;
+ ReadDIB(aBitmap, aBitmapStream, /*bFileHeader=*/true);
+ Size aBitmapSize = aBitmap.GetSizePixel();
+ BitmapEx aBitmapEx(aBitmap);
+ Color nActualColor
+ = aBitmapEx.GetPixelColor(aBitmapSize.getWidth() - 1, aBitmapSize.getHeight() - 1);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: Color: R:255 G:255 B:255 A:0
+ // - Actual : Color: R:0 G:0 B:0 A:0
+ // i.e. the bitmap without an alpha channel was black, not white.
+ CPPUNIT_ASSERT_EQUAL(COL_WHITE, nActualColor);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testListsHeading)
+{
+ // Given a document with lh, lh, li, li, lh and lh nodes:
+ createSwDoc();
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("list 1, header 1");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("list 1, header 2");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("list 2, item 1");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("list 2, item 2");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("list 3, header 1");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("list 3, header 2");
+ SwDoc* pDoc = pWrtShell->GetDoc();
+ pWrtShell->Up(false, 5);
+ {
+ sal_uInt16 nPos = pDoc->MakeNumRule(pDoc->GetUniqueNumRuleName());
+ SwNumRule* pNumRule = pDoc->GetNumRuleTable()[nPos];
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ rTextNode.SetCountedInList(false);
+ }
+ pWrtShell->Down(false, 1);
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ rTextNode.SetCountedInList(false);
+ }
+ }
+ pWrtShell->Down(false, 1);
+ {
+ sal_uInt16 nPos = pDoc->MakeNumRule(pDoc->GetUniqueNumRuleName());
+ SwNumRule* pNumRule = pDoc->GetNumRuleTable()[nPos];
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ }
+ pWrtShell->Down(false, 1);
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ }
+ }
+ pWrtShell->Down(false, 1);
+ {
+ sal_uInt16 nPos = pDoc->MakeNumRule(pDoc->GetUniqueNumRuleName());
+ SwNumRule* pNumRule = pDoc->GetNumRuleTable()[nPos];
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ rTextNode.SetCountedInList(false);
+ }
+ pWrtShell->Down(false, 1);
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ rTextNode.SetCountedInList(false);
+ }
+ }
+
+ // When exporting to ReqIF:
+ ExportToReqif();
+
+ // Then make sure the output is valid xhtml:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+
+ OUString aContent
+ = getXPathContent(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ol/"
+ "reqif-xhtml:li[@style='display: block']/reqif-xhtml:p"_ostr);
+ CPPUNIT_ASSERT_EQUAL(OUString("list 1, header 1"), aContent.trim());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testOleEmfPreviewToHtml)
+{
+ // Given a document containing an embedded object, with EMF preview:
+ createSwDoc("ole2.odt");
+
+ // When exporting to HTML:
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ // Then make sure the <img> tag has matching file extension and data:
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ OUString aPath = getXPath(pDoc, "/html/body/p/img"_ostr, "src"_ostr);
+ // Without the accompanying fix in place, this test would have failed, as aPath was
+ // ole_html_3978e5f373402b43.JPG, with EMF data.
+ CPPUNIT_ASSERT(aPath.endsWith("gif"));
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testNestedBullets)
+{
+ // Given a documented with nested lists:
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("first");
+ sal_uInt16 nPos = pDoc->MakeNumRule(pDoc->GetUniqueNumRuleName());
+ SwNumRule* pNumRule = pDoc->GetNumRuleTable()[nPos];
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ rTextNode.SetAttrListLevel(0);
+ }
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("second");
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ rTextNode.SetAttrListLevel(1);
+ }
+
+ // When exporting to xhtml:
+ ExportToReqif();
+
+ // Then make sure that there is a <li> between the outer and the inner <ol>:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - XPath '//reqif-xhtml:ol/reqif-xhtml:li/reqif-xhtml:ol/reqif-xhtml:li/reqif-xhtml:p' not found
+ // i.e. the <li> inside the outer <ol> was missing.
+ assertXPathContent(
+ pXmlDoc, "//reqif-xhtml:ol/reqif-xhtml:li/reqif-xhtml:ol/reqif-xhtml:li/reqif-xhtml:p"_ostr,
+ "second");
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTrailingLineBreak)
+{
+ // Given a document with a trailing line-break:
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("test\n");
+
+ // When exporting to reqif-xhtml:
+ ExportToReqif();
+
+ // Then make sure that we still have a single line-break:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 2
+ // - XPath '//reqif-xhtml:br' number of nodes is incorrect
+ assertXPath(pXmlDoc, "//reqif-xhtml:br"_ostr, 1);
+
+ // Then test the import side:
+
+ // Given an empty document:
+ mxComponent->dispose();
+
+ // When importing a <br> from reqif-xhtml:
+ ImportFromReqif(maTempFile.GetURL());
+
+ // Then make sure that line-break is not lost:
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ pDoc = pTextDoc->GetDocShell()->GetDoc();
+ pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ OUString aActual = pWrtShell->GetCursor()->GetPointNode().GetTextNode()->GetText();
+ // Without the accompanying fix in place, this test would have failed, as the trailing
+ // line-break was lost.
+ CPPUNIT_ASSERT_EQUAL(OUString("test\n"), aActual);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testLeadingTab)
+{
+ // Given a document with leading tabs:
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("\t first");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("\t\t second");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("thi \t rd");
+
+ // When exporting to HTML, using LeadingTabWidth=2:
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ comphelper::makePropertyValue("LeadingTabWidth", static_cast<sal_Int32>(2)),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ // Then make sure that leading tabs are replaced with 2 nbsps:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: <nbsp><nbsp><space>first
+ // - Actual : <tab><space>first
+ // i.e. the leading tab was not replaced by 2 nbsps.
+ assertXPathContent(pXmlDoc, "//reqif-xhtml:p[1]"_ostr, u"\xa0\xa0 first"_ustr);
+ // Test a leading tab that is not at the start of the paragraph:
+ assertXPathContent(pXmlDoc, "//reqif-xhtml:p[2]"_ostr, u"\xa0\xa0\xa0\xa0 second"_ustr);
+ // Test a tab which is not leading:
+ assertXPathContent(pXmlDoc, "//reqif-xhtml:p[3]"_ostr, u"thi \t rd"_ustr);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testLeadingTabHTML)
+{
+ // Given a document with leading tabs:
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("\t test");
+
+ // When exporting to plain HTML, using LeadingTabWidth=2:
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("LeadingTabWidth", static_cast<sal_Int32>(2)),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ // Then make sure that leading tabs are replaced with 2 nbsps:
+ htmlDocUniquePtr pHtmlDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pHtmlDoc);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: <newline><nbsp><nbsp><space>test
+ // - Actual : <newline><tab><space>test
+ // i.e. the leading tab was not replaced by 2 nbsps.
+ assertXPathContent(pHtmlDoc, "/html/body/p"_ostr, SAL_NEWLINE_STRING u"\xa0\xa0 test"_ustr);
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testClearingBreak)
+{
+ auto verify = [this]() {
+ uno::Reference<container::XEnumerationAccess> xParagraph(getParagraph(1), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortions = xParagraph->createEnumeration();
+ uno::Reference<beans::XPropertySet> xPortion;
+ OUString aPortionType;
+ while (true)
+ {
+ // Ignore leading comments.
+ xPortion.set(xPortions->nextElement(), uno::UNO_QUERY);
+ xPortion->getPropertyValue("TextPortionType") >>= aPortionType;
+ if (aPortionType != "Annotation")
+ {
+ break;
+ }
+ }
+ // Skip "foo".
+ // Without the accompanying fix in place, this test would have failed with:
+ // An uncaught exception of type com.sun.star.container.NoSuchElementException
+ // i.e. the first para was just comments + text portion, the clearing break was lost.
+ xPortion.set(xPortions->nextElement(), uno::UNO_QUERY);
+ xPortion->getPropertyValue("TextPortionType") >>= aPortionType;
+ CPPUNIT_ASSERT_EQUAL(OUString("LineBreak"), aPortionType);
+ uno::Reference<text::XTextContent> xLineBreak;
+ xPortion->getPropertyValue("LineBreak") >>= xLineBreak;
+ sal_Int16 eClear{};
+ uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY);
+ xLineBreakProps->getPropertyValue("Clear") >>= eClear;
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(SwLineBreakClear::ALL), eClear);
+ };
+
+ // Given a document with an at-para anchored image + a clearing break:
+ // When loading that file:
+ createSwWebDoc("clearing-break.html");
+ // Then make sure that the clear property of the break is not ignored:
+ verify();
+ saveAndReload("HTML (StarWriter)");
+ // Make sure that the clear property of the break is not ignored during export:
+ verify();
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTableBackground)
+{
+ // Given a document with two tables: first stable has a background, second table has a
+ // background in its first row:
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ SwInsertTableOptions aInsertTableOptions(SwInsertTableFlags::DefaultBorder,
+ /*nRowsToRepeat=*/0);
+ pWrtShell->InsertTable(aInsertTableOptions, /*nRows=*/1, /*nCols=*/1);
+ pWrtShell->MoveTable(GotoPrevTable, fnTableStart);
+ SvxBrushItem aBrush(Color(0xff0000), RES_BACKGROUND);
+ pWrtShell->SetTabBackground(aBrush);
+ pWrtShell->Down(/*bSelect=*/false);
+ pWrtShell->SplitNode();
+ pWrtShell->InsertTable(aInsertTableOptions, /*nRows=*/2, /*nCols=*/1);
+ pWrtShell->MoveTable(GotoPrevTable, fnTableStart);
+ aBrush.SetColor(0x00ff00);
+ pWrtShell->SetRowBackground(aBrush);
+ pWrtShell->Down(/*bSelect=*/false);
+ // Second row has an explicit transparent background.
+ aBrush.SetColor(COL_TRANSPARENT);
+ pWrtShell->SetRowBackground(aBrush);
+
+ // When exporting to reqif-xhtml:
+ ExportToReqif();
+
+ // Then make sure that CSS markup is used, not HTML one:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - XPath '//reqif-xhtml:table[1]' no attribute 'style' exist
+ // i.e. HTML markup was used for the table background color.
+ assertXPath(pXmlDoc, "//reqif-xhtml:table[1]"_ostr, "style"_ostr, "background: #ff0000");
+ assertXPathNoAttribute(pXmlDoc, "//reqif-xhtml:table[1]"_ostr, "bgcolor"_ostr);
+ assertXPath(pXmlDoc, "//reqif-xhtml:table[2]/reqif-xhtml:tr[1]"_ostr, "style"_ostr,
+ "background: #00ff00");
+ assertXPathNoAttribute(pXmlDoc, "//reqif-xhtml:table[2]/reqif-xhtml:tr[1]"_ostr,
+ "bgcolor"_ostr);
+ // Second row has no explicit style, the default is not written.
+ assertXPathNoAttribute(pXmlDoc, "//reqif-xhtml:table[2]/reqif-xhtml:tr[2]"_ostr, "style"_ostr);
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testImageKeepRatio)
+{
+ // Given a document with an image: width is relative, height is "keep ratio":
+ createSwDoc();
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xTextGraphic(
+ xFactory->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY);
+ xTextGraphic->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AS_CHARACTER));
+ xTextGraphic->setPropertyValue("RelativeWidth", uno::Any(static_cast<sal_Int16>(42)));
+ xTextGraphic->setPropertyValue("IsSyncHeightToWidth", uno::Any(true));
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xBodyText = xTextDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor(xBodyText->createTextCursor());
+ uno::Reference<text::XTextContent> xTextContent(xTextGraphic, uno::UNO_QUERY);
+ xBodyText->insertTextContent(xCursor, xTextContent, false);
+
+ // When exporting to HTML:
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ // Then make sure that the width is not a fixed size, that would break on resizing the browser
+ // window:
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: auto
+ // - Actual : 2
+ // i.e. a static (CSS pixel) height was written.
+ assertXPath(pDoc, "/html/body/p/img"_ostr, "height"_ostr, "auto");
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testSectionDir)
+{
+ // Given a document with a section:
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("test");
+ pWrtShell->SelAll();
+ SwSectionData aSectionData(SectionType::Content, "mysect");
+ pWrtShell->InsertSection(aSectionData);
+
+ // When exporting to (reqif-)xhtml:
+ ExportToReqif();
+
+ // Then make sure CSS is used to export the text direction of the section:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - XPath '//reqif-xhtml:div[@id='mysect']' no attribute 'style' exist
+ // i.e. the dir="ltr" HTML attribute was used instead.
+ assertXPath(pXmlDoc, "//reqif-xhtml:div[@id='mysect']"_ostr, "style"_ostr, "dir: ltr");
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testTdf114769)
+{
+ // Create document from scratch since relative urls to filesystem can be replaced
+ // by absolute during save/load
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("Hyperlink1");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("Hyperlink2");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("Hyperlink3");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("Hyperlink4");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("Hyperlink5");
+ pWrtShell->SplitNode();
+
+ // Normal external URL
+ uno::Reference<beans::XPropertySet> xRun(getRun(getParagraph(1), 1), uno::UNO_QUERY);
+ xRun->setPropertyValue("HyperLinkURL", uno::Any(OUString("http://libreoffice.org/")));
+
+ // Bookmark reference
+ xRun.set(getRun(getParagraph(2), 1), uno::UNO_QUERY);
+ xRun->setPropertyValue("HyperLinkURL", uno::Any(OUString("#some_bookmark")));
+
+ // Filesystem absolute link
+ xRun.set(getRun(getParagraph(3), 1), uno::UNO_QUERY);
+ xRun->setPropertyValue("HyperLinkURL", uno::Any(OUString("C:\\test.txt")));
+
+ // Filesystem relative link
+ xRun.set(getRun(getParagraph(4), 1), uno::UNO_QUERY);
+ xRun->setPropertyValue("HyperLinkURL", uno::Any(OUString("..\\..\\test.odt")));
+
+ // Filesystem relative link
+ xRun.set(getRun(getParagraph(5), 1), uno::UNO_QUERY);
+ xRun->setPropertyValue("HyperLinkURL", uno::Any(OUString(".\\another.odt")));
+
+ // Export
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties
+ = { comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")) };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ htmlDocUniquePtr pHtmlDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pHtmlDoc);
+
+ CPPUNIT_ASSERT_EQUAL(OUString("http://libreoffice.org/"),
+ getXPath(pHtmlDoc, "/html/body/p[1]/a"_ostr, "href"_ostr));
+ CPPUNIT_ASSERT_EQUAL(OUString("#some_bookmark"),
+ getXPath(pHtmlDoc, "/html/body/p[2]/a"_ostr, "href"_ostr));
+ CPPUNIT_ASSERT_EQUAL(OUString("C:\\test.txt"),
+ getXPath(pHtmlDoc, "/html/body/p[3]/a"_ostr, "href"_ostr));
+ CPPUNIT_ASSERT_EQUAL(OUString("..\\..\\test.odt"),
+ getXPath(pHtmlDoc, "/html/body/p[4]/a"_ostr, "href"_ostr));
+ CPPUNIT_ASSERT_EQUAL(OUString(".\\another.odt"),
+ getXPath(pHtmlDoc, "/html/body/p[5]/a"_ostr, "href"_ostr));
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testTdf153923)
+{
+ createSwDoc("TableWithIndent.fodt");
+ save("HTML (StarWriter)");
+
+ // Parse it as XML (strict!)
+ xmlDocUniquePtr pDoc = parseXml(maTempFile);
+ // Without the fix in place, this would fail
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPath(pDoc, "/html/body//dl"_ostr, 3);
+ // The 'dd' tag was not closed
+ assertXPath(pDoc, "/html/body//dd"_ostr, 3);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTdf153923_ReqIF)
+{
+ createSwDoc("TableWithIndent.fodt");
+ ExportToReqif();
+
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ assertXPath(pDoc, "//reqif-xhtml:table"_ostr);
+ // There should be no 'dd' or 'dl' tags, used as a hack for table indentation
+ assertXPath(pDoc, "//reqif-xhtml:dl"_ostr, 0);
+ assertXPath(pDoc, "//reqif-xhtml:dd"_ostr, 0);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIfTransparentTifImg)
+{
+ // reqIf export must keep the TIF encoding of the image
+ createSwDoc("reqif-transparent-tif-img.odt");
+ ExportToReqif();
+
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ assertXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object[1]"_ostr, "type"_ostr, "image/tiff");
+ OUString imageName
+ = getXPath(pXmlDoc, "//reqif-xhtml:p/reqif-xhtml:object[1]"_ostr, "data"_ostr);
+ // Without the accompanying fix in place, this test would have failed,
+ // ending with .gif, because XOutFlags::UseGifIfSensible flag combined
+ // with the transparent image would result in GIF export
+ CPPUNIT_ASSERT(imageName.endsWith(".tif"));
+
+ INetURLObject aURL(maTempFile.GetURL());
+ aURL.setName(imageName);
+ GraphicDescriptor aDescriptor(aURL);
+ aDescriptor.Detect();
+ CPPUNIT_ASSERT_EQUAL(GraphicFileFormat::TIF, aDescriptor.GetFileFormat());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTdf155387)
+{
+ createSwDoc("sub_li_and_ctd.fodt");
+ ExportToReqif();
+
+ // Without the fix in place, this would fail
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // Single top-level list
+ assertXPath(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ul"_ostr);
+ // Single top-level item
+ assertXPath(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ul/reqif-xhtml:li"_ostr);
+ // 4 top-level paragraphs in the item
+ assertXPath(
+ pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ul/reqif-xhtml:li/reqif-xhtml:p"_ostr,
+ 4);
+ // 2 sublists in the item
+ assertXPath(
+ pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ul/reqif-xhtml:li/reqif-xhtml:ul"_ostr,
+ 2);
+ // 2 items in the first sublist
+ assertXPath(pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ul/reqif-xhtml:li/reqif-xhtml:ul[1]/"
+ "reqif-xhtml:li"_ostr,
+ 2);
+ // Check the last (most nested) subitem's text
+ assertXPathContent(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ul/reqif-xhtml:li/reqif-xhtml:ul[2]/"
+ "reqif-xhtml:li/reqif-xhtml:ul/reqif-xhtml:li/reqif-xhtml:p"_ostr,
+ "l3");
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTdf155496)
+{
+ createSwDoc("listItemSubheader.fodt");
+ ExportToReqif();
+
+ // Without the fix in place, this would fail
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // Two top-level lists
+ assertXPath(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ul"_ostr, 2);
+ // Single top-level item
+ assertXPath(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ul[1]/reqif-xhtml:li"_ostr);
+ // One top-level paragraph in the item
+ assertXPath(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ul[1]/reqif-xhtml:li/reqif-xhtml:p"_ostr);
+ // One sublist in the item
+ assertXPath(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ul[1]/reqif-xhtml:li/reqif-xhtml:ul"_ostr);
+ // One item in the sublist
+ assertXPath(pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ul[1]/reqif-xhtml:li/reqif-xhtml:ul/"
+ "reqif-xhtml:li"_ostr);
+ // Check its text
+ OUString aContent = getXPathContent(
+ pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ul[1]/reqif-xhtml:li/reqif-xhtml:ul/"
+ "reqif-xhtml:li/reqif-xhtml:p"_ostr);
+ CPPUNIT_ASSERT_EQUAL(OUString("list 1 item 1\n\t\tsub-header"), aContent.trim());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_RightAlignedTable)
+{
+ createSwDoc("tableRight.fodt");
+ ExportToReqif();
+
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // No 'align' attribute must be present in 'div'
+ assertXPathNoAttribute(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:div"_ostr,
+ "align"_ostr);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_ListsWithNumFormat)
+{
+ createSwDoc("listsWithNumFormat.fodt");
+ ExportToReqif();
+
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // No 'type' attribute must be present in 'ol'
+ assertXPathNoAttribute(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ol[1]"_ostr,
+ "type"_ostr);
+ assertXPathNoAttribute(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ol[2]"_ostr,
+ "type"_ostr);
+ assertXPathNoAttribute(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ol[3]"_ostr,
+ "type"_ostr);
+ assertXPathNoAttribute(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ol[4]"_ostr,
+ "type"_ostr);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTdf155871)
+{
+ createSwDoc("tdf155871.fodt");
+ ExportToReqif();
+
+ // Without the fix in place, this would fail
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_ListsNoStartAttribute)
+{
+ createSwDoc("twoListsWithSameStyle.fodt");
+ ExportToReqif();
+
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // No 'start' attribute must be present in 'ol'
+ assertXPath(pDoc, "//reqif-xhtml:ol[@start]"_ostr, 0);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_FrameTextAsObjectAltText)
+{
+ createSwDoc("frameWithText.fodt");
+ ExportToReqif();
+
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // Without the fix, this would fail with
+ // - Expected: Some text in frame & <foo>
+ // - Actual : Frame1
+ // i.e., frame name was used as the object element content, not frame text
+ assertXPathContent(pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[2]/reqif-xhtml:object"_ostr,
+ "Some text in frame & <foo>");
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testSingleOleExport)
+{
+ // Given a document containing an embedded OLE object:
+ createSwDoc("ole2.odt");
+
+ // Create a selection for that object:
+ auto xDrawPageSupplier(mxComponent.queryThrow<css::drawing::XDrawPageSupplier>());
+ auto xDrawPage(xDrawPageSupplier->getDrawPage());
+ auto xModel(mxComponent.queryThrow<css::frame::XModel>());
+ auto xController(xModel->getCurrentController().queryThrow<css::view::XSelectionSupplier>());
+ xController->select(xDrawPage->getByIndex(0));
+
+ // Store only the selection
+ auto xStorable(mxComponent.queryThrow<css::frame::XStorable>());
+ css::uno::Sequence<css::beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ comphelper::makePropertyValue("RTFOLEMimeType", OUString("text/rtf")),
+ comphelper::makePropertyValue("SelectionOnly", true),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+
+ // The root element must be reqif-xhtml:object
+ assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:object"_ostr, "type"_ostr, "text/rtf");
+ // It has no children
+ assertXPathChildren(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:object"_ostr, 0);
+ // And the content is empty
+ assertXPathContent(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:object"_ostr, "");
+
+ OUString aRtfData = getXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:object"_ostr, "data"_ostr);
+ INetURLObject aUrl(maTempFile.GetURL());
+ aUrl.setName(aRtfData);
+ SvMemoryStream aRtf;
+ HtmlExportTest::wrapRtfFragment(aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE), aRtf);
+ tools::SvRef<TestReqIfRtfReader> xReader(new TestReqIfRtfReader(aRtf));
+ // The RTF OLE exports correctly
+ CPPUNIT_ASSERT(xReader->CallParser() != SvParserState::Error);
+ CPPUNIT_ASSERT_EQUAL(tools::Long(9358), xReader->GetObjw());
+ CPPUNIT_ASSERT_EQUAL(tools::Long(450), xReader->GetObjh());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_Tdf156602)
+{
+ createSwDoc("NestingInA1.fodt");
+ ExportToReqif();
+
+ xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
+
+ // The outer table must be kept in the document where the outer table is the first element,
+ // and its A1 starts with a nested table
+
+ // Only two sub-elements must be inside the div: an outer table and a trailing paragraph
+ assertXPathChildren(pDoc, "/reqif-xhtml:html/reqif-xhtml:div"_ostr, 2);
+ // The outer table must have exactly two rows
+ assertXPath(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr"_ostr, 2);
+ // First outer table cell must have two sub-elements: an inner table and a trailing paragraph
+ assertXPathChildren(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr[1]/reqif-xhtml:td[1]"_ostr,
+ 2);
+ // The inner table must have exactly two rows
+ assertXPath(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr[1]/reqif-xhtml:td[1]/"
+ "reqif-xhtml:table/reqif-xhtml:tr"_ostr,
+ 2);
+ // Check all the elements' content
+ assertXPathContent(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr[1]/reqif-xhtml:td[1]/"
+ "reqif-xhtml:table/reqif-xhtml:tr[1]/reqif-xhtml:td[1]/reqif-xhtml:p"_ostr,
+ "Inner.A1");
+ assertXPathContent(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr[1]/reqif-xhtml:td[1]/"
+ "reqif-xhtml:table/reqif-xhtml:tr[1]/reqif-xhtml:td[2]/reqif-xhtml:p"_ostr,
+ "Inner.B1");
+ assertXPathContent(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr[1]/reqif-xhtml:td[1]/"
+ "reqif-xhtml:table/reqif-xhtml:tr[2]/reqif-xhtml:td[1]/reqif-xhtml:p"_ostr,
+ "Inner.A2");
+ assertXPathContent(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr[1]/reqif-xhtml:td[1]/"
+ "reqif-xhtml:table/reqif-xhtml:tr[2]/reqif-xhtml:td[2]/reqif-xhtml:p"_ostr,
+ "Inner.B2");
+ assertXPathContent(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr[1]/reqif-xhtml:td[1]/"
+ "reqif-xhtml:p"_ostr,
+ "Outer.A1");
+ assertXPathContent(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr[1]/reqif-xhtml:td[2]/"
+ "reqif-xhtml:p"_ostr,
+ "Outer.B1");
+ assertXPathContent(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr[2]/reqif-xhtml:td[1]/"
+ "reqif-xhtml:p"_ostr,
+ "Outer.A2");
+ assertXPathContent(
+ pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr[2]/reqif-xhtml:td[2]/"
+ "reqif-xhtml:p"_ostr,
+ "Outer.B2");
+ assertXPathContent(pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p"_ostr,
+ "Following text");
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTdf156647_CellPaddingRoundtrip)
+{
+ // Given a document with a table with cell padding:
+ createSwDoc("table_cell_padding.fodt");
+ {
+ auto xTable = getParagraphOrTable(1);
+ auto aTableBorder = getProperty<css::table::TableBorder2>(xTable, "TableBorder2");
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(1270), aTableBorder.Distance);
+ CPPUNIT_ASSERT(aTableBorder.IsDistanceValid);
+ }
+ // When exporting to reqif-xhtml:
+ ExportToReqif();
+ // Make sure that we export it:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ assertXPath(pXmlDoc, "//reqif-xhtml:table"_ostr, "cellpadding"_ostr, "48"); // px
+ // Now import it
+ mxComponent->dispose();
+ ImportFromReqif(maTempFile.GetURL());
+ // Then make sure that padding is not lost:
+ {
+ auto xTable = getParagraphOrTable(1);
+ auto aTableBorder = getProperty<css::table::TableBorder2>(xTable, "TableBorder2");
+ // Without the accompanying fix in place, this test would have failed:
+ // - Expected: 1270
+ // - Actual : 97
+ // as the padding was lost, and the default 55 twip padding was used.
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(1270), aTableBorder.Distance);
+ CPPUNIT_ASSERT(aTableBorder.IsDistanceValid);
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTdf157643_WideHBorder)
+{
+ // Given a document with a table with a wide border between its two rows:
+ createSwDoc("table_with_wide_horizontal_border.fodt");
+ // When exporting to reqif-xhtml:
+ ExportToReqif();
+ // Make sure that there's no extra tr's:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr"_ostr,
+ 2);
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testHTML_PreserveSpaces)
+{
+ // Given a document with leading, trailing, and repeating intermediate spaces:
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ constexpr OUString paraText = u"\t test \t more text \t"_ustr;
+ pWrtShell->Insert(paraText);
+
+ // When exporting to plain HTML, using PreserveSpaces:
+ saveWithParams({
+ comphelper::makePropertyValue("FilterName", u"HTML (StarWriter)"_ustr),
+ comphelper::makePropertyValue("PreserveSpaces", true),
+ });
+
+ // Then make sure that "white-space: pre-wrap" is written into the paragraph's style:
+ htmlDocUniquePtr pHtmlDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pHtmlDoc);
+ const OUString style = getXPath(pHtmlDoc, "/html/body/p"_ostr, "style"_ostr);
+ CPPUNIT_ASSERT(style.indexOf("white-space: pre-wrap") >= 0);
+ // Also check that the paragraph text is correct, without modifications in whitespace
+ assertXPathContent(pHtmlDoc, "/html/body/p"_ostr, paraText);
+
+ // Test import
+
+ setImportFilterName("HTML (StarWriter)");
+ load(maTempFile.GetURL());
+ CPPUNIT_ASSERT_EQUAL(paraText, getParagraph(1)->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_PreserveSpaces)
+{
+ // Given a document with leading, trailing, and repeating intermediate spaces:
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ constexpr OUString paraText = u"\t test \t more text \t"_ustr;
+ pWrtShell->Insert(paraText);
+
+ // When exporting to ReqIF, using PreserveSpaces:
+ saveWithParams({
+ comphelper::makePropertyValue("FilterName", u"HTML (StarWriter)"_ustr),
+ comphelper::makePropertyValue("FilterOptions", u"xhtmlns=reqif-xhtml"_ustr),
+ comphelper::makePropertyValue("PreserveSpaces", true),
+ });
+
+ // Then make sure that xml:space="preserve" attribute exists in the paragraph element:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p"_ostr, "space"_ostr,
+ u"preserve"_ustr);
+ // Also check that the paragraph text is correct, without modifications in whitespace
+ assertXPathContent(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p"_ostr, paraText);
+
+ // Test import
+
+ setImportFilterOptions("xhtmlns=reqif-xhtml");
+ setImportFilterName("HTML (StarWriter)");
+ load(maTempFile.GetURL());
+ CPPUNIT_ASSERT_EQUAL(paraText, getParagraph(1)->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testHTML_NoPreserveSpaces)
+{
+ // Test cases where "PreserveSpaces" should not introduce respective markup
+
+ const auto assertXPath_NoWhiteSpaceInStyle
+ = [this](const xmlDocUniquePtr& pDoc, const OString& rXPath) {
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pDoc, rXPath);
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(rXPath.getStr(), 1, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
+ if (xmlChar* prop = xmlGetProp(pXmlNode, BAD_CAST("style")))
+ {
+ OUString style = OUString::fromUtf8(reinterpret_cast<const char*>(prop));
+ CPPUNIT_ASSERT_MESSAGE(rXPath.getStr(), style.indexOf("white-space:") < 0);
+ }
+ xmlXPathFreeObject(pXmlObj);
+ };
+ const auto assertXPath_HasWhiteSpaceInStyle
+ = [this](const xmlDocUniquePtr& pDoc, const OString& rXPath) {
+ const OUString style = getXPath(pDoc, rXPath, "style"_ostr);
+ CPPUNIT_ASSERT_MESSAGE(rXPath.getStr(), style.indexOf("white-space: pre-wrap") >= 0);
+ };
+
+ createSwDoc("test_no_space_preserve.fodt");
+
+ // Export to plain HTML, using PreserveSpaces:
+ saveWithParams({
+ comphelper::makePropertyValue("FilterName", u"HTML (StarWriter)"_ustr),
+ comphelper::makePropertyValue("PreserveSpaces", true),
+ });
+
+ htmlDocUniquePtr pHtmlDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pHtmlDoc);
+
+ // No whitespace preservation, where no leading / trailing / double whitespace
+ assertXPath_NoWhiteSpaceInStyle(pHtmlDoc, "/html/body/p[1]"_ostr);
+ // Whitespace preserved for a leading space
+ assertXPath_HasWhiteSpaceInStyle(pHtmlDoc, "/html/body/p[2]"_ostr);
+ // Whitespace preserved for a trailing space
+ assertXPath_HasWhiteSpaceInStyle(pHtmlDoc, "/html/body/p[3]"_ostr);
+ // Whitespace preserved for a double space
+ assertXPath_HasWhiteSpaceInStyle(pHtmlDoc, "/html/body/p[4]"_ostr);
+ // No whitespace preservation for leading / trailing breaks
+ assertXPath_NoWhiteSpaceInStyle(pHtmlDoc, "/html/body/p[5]"_ostr);
+ // Whitespace preserved for a leading break + space
+ assertXPath_HasWhiteSpaceInStyle(pHtmlDoc, "/html/body/p[6]"_ostr);
+ // Whitespace preserved for a trailing space + break
+ assertXPath_HasWhiteSpaceInStyle(pHtmlDoc, "/html/body/p[7]"_ostr);
+ // No whitespace preservation for a middle break
+ assertXPath_NoWhiteSpaceInStyle(pHtmlDoc, "/html/body/p[8]"_ostr);
+ // Whitespace preserved for a middle space + break
+ assertXPath_HasWhiteSpaceInStyle(pHtmlDoc, "/html/body/p[9]"_ostr);
+ // Whitespace preserved for a middle break + space
+ assertXPath_HasWhiteSpaceInStyle(pHtmlDoc, "/html/body/p[10]"_ostr);
+ // No whitespace preservation for a trailing space and SVG
+ assertXPath_NoWhiteSpaceInStyle(pHtmlDoc, "/html/body/p[11]"_ostr);
+
+ // Test import
+
+ setImportFilterName("HTML (StarWriter)");
+ load(maTempFile.GetURL());
+
+ CPPUNIT_ASSERT_EQUAL(u"No special spaces"_ustr, getParagraph(1)->getString());
+ CPPUNIT_ASSERT_EQUAL(u" Leading space"_ustr, getParagraph(2)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"Trailing space "_ustr, getParagraph(3)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"Double space"_ustr, getParagraph(4)->getString());
+ // Trailing break is removed in SwHTMLParser::AppendTextNode, and replaced with para spacing
+ CPPUNIT_ASSERT_EQUAL(u"\nLeading/trailing breaks"_ustr, getParagraph(5)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"\n Leading break + space"_ustr, getParagraph(6)->getString());
+ // Trailing break is removed in SwHTMLParser::AppendTextNode, and replaced with para spacing
+ CPPUNIT_ASSERT_EQUAL(u"Trailing space + break "_ustr, getParagraph(7)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"Middle\nbreak"_ustr, getParagraph(8)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"Middle space \n+ break"_ustr, getParagraph(9)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"Middle break\n + space"_ustr, getParagraph(10)->getString());
+ // The SVG is replaced by a space in SwXParagraph::getString()
+ CPPUNIT_ASSERT_EQUAL(u"Trailing space and SVG "_ustr, getParagraph(11)->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_NoPreserveSpaces)
+{
+ // Test cases where "PreserveSpaces" should not introduce respective markup
+
+ createSwDoc("test_no_space_preserve.fodt");
+
+ // Export to ReqIF, using PreserveSpaces:
+ saveWithParams({
+ comphelper::makePropertyValue("FilterName", u"HTML (StarWriter)"_ustr),
+ comphelper::makePropertyValue("FilterOptions", u"xhtmlns=reqif-xhtml"_ustr),
+ comphelper::makePropertyValue("PreserveSpaces", true),
+ });
+
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+
+ // No whitespace preservation, where no leading / trailing / double whitespace
+ assertXPathNoAttribute(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[1]"_ostr,
+ "space"_ostr);
+ // Whitespace preserved for a leading space
+ assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[2]"_ostr, "space"_ostr,
+ u"preserve"_ustr);
+ // Whitespace preserved for a trailing space
+ assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[3]"_ostr, "space"_ostr,
+ u"preserve"_ustr);
+ // Whitespace preserved for a double space
+ assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[4]"_ostr, "space"_ostr,
+ u"preserve"_ustr);
+ // No whitespace preservation for leading / trailing breaks
+ assertXPathNoAttribute(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[5]"_ostr,
+ "space"_ostr);
+ // Whitespace preserved for a leading break + space
+ assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[6]"_ostr, "space"_ostr,
+ u"preserve"_ustr);
+ // No whitespace preservation for a trailing space + break
+ assertXPathNoAttribute(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[7]"_ostr,
+ "space"_ostr);
+ // No whitespace preservation for a middle break
+ assertXPathNoAttribute(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[8]"_ostr,
+ "space"_ostr);
+ // No whitespace preservation for a middle space + break
+ assertXPathNoAttribute(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[9]"_ostr,
+ "space"_ostr);
+ // Whitespace preserved for a middle break + space
+ assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[10]"_ostr, "space"_ostr,
+ u"preserve"_ustr);
+ // No whitespace preservation for a trailing space and SVG
+ assertXPathNoAttribute(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[11]"_ostr,
+ "space"_ostr);
+
+ // Test import
+
+ setImportFilterOptions("xhtmlns=reqif-xhtml");
+ setImportFilterName("HTML (StarWriter)");
+ load(maTempFile.GetURL());
+
+ CPPUNIT_ASSERT_EQUAL(u"No special spaces"_ustr, getParagraph(1)->getString());
+ CPPUNIT_ASSERT_EQUAL(u" Leading space"_ustr, getParagraph(2)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"Trailing space "_ustr, getParagraph(3)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"Double space"_ustr, getParagraph(4)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"\nLeading/trailing breaks\n"_ustr, getParagraph(5)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"\n Leading break + space"_ustr, getParagraph(6)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"Trailing space + break \n"_ustr, getParagraph(7)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"Middle\nbreak"_ustr, getParagraph(8)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"Middle space \n+ break"_ustr, getParagraph(9)->getString());
+ CPPUNIT_ASSERT_EQUAL(u"Middle break\n + space"_ustr, getParagraph(10)->getString());
+ // The SVG is replaced by a space in SwXParagraph::getString()
+ CPPUNIT_ASSERT_EQUAL(u"Trailing space and SVG "_ustr, getParagraph(11)->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_ExportFormulasAsPDF)
+{
+ // Given a document with a formula:
+ createSwDoc("embedded_formula.fodt");
+
+ // When exporting to reqif with ExportFormulasAsPDF=true:
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY_THROW);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue(u"FilterName"_ustr, u"HTML (StarWriter)"_ustr),
+ comphelper::makePropertyValue(u"FilterOptions"_ustr, u"xhtmlns=reqif-xhtml"_ustr),
+ comphelper::makePropertyValue(u"ExportFormulasAsPDF"_ustr, true),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ // Make sure that the formula is exported as PDF:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ assertXPath(pXmlDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[2]/reqif-xhtml:object"_ostr,
+ "type"_ostr, u"application/pdf"_ustr);
+
+ css::uno::Sequence<css::beans::PropertyValue> descr{
+ comphelper::makePropertyValue(u"URL"_ustr, GetObjectPath(u".pdf"_ustr)),
+ };
+
+ uno::Reference<lang::XMultiServiceFactory> xFactory(
+ comphelper::getProcessComponentContext()->getServiceManager(), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XTypeDetection> xTypeDetection(
+ xFactory->createInstance(u"com.sun.star.document.TypeDetection"_ustr),
+ uno::UNO_QUERY_THROW);
+
+ CPPUNIT_ASSERT_EQUAL(u"pdf_Portable_Document_Format"_ustr,
+ xTypeDetection->queryTypeByDescriptor(descr, true));
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_NoBrClearForImageWrap)
+{
+ // Given a document with a paragraph-anchored image with "none" wrap:
+ createSwDoc("image_anchored_to_paragraph_no_wrap.fodt");
+ // When exporting to reqif:
+ ExportToReqif();
+ // Make sure that there's no 'br' elements in the 'object' (used to represent the wrapping
+ // in HTML export, using 'clear' attribute):
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object"_ostr);
+ assertXPath(
+ pXmlDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object/reqif-xhtml:br"_ostr,
+ 0);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/htmlexport/xhtmlexport.cxx b/sw/qa/extras/htmlexport/xhtmlexport.cxx
new file mode 100644
index 0000000000..86026dbd70
--- /dev/null
+++ b/sw/qa/extras/htmlexport/xhtmlexport.cxx
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <memory>
+#include <swmodeltestbase.hxx>
+
+#include <test/htmltesttools.hxx>
+
+class XHtmlExportTest : public SwModelTestBase, public HtmlTestTools
+{
+public:
+ XHtmlExportTest()
+ : SwModelTestBase("/sw/qa/extras/odfexport/data/", "XHTML Writer File")
+ {
+ }
+};
+
+CPPUNIT_TEST_FIXTURE(XHtmlExportTest, testImageEmbedding)
+{
+ createSwDoc("image-mimetype.odt");
+ setFilterOptions("UTF8");
+ save(mpFilter);
+ htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPath(pDoc, "/html/body"_ostr, 1);
+ assertXPath(pDoc, "/html/body/div[1]/div[1]/img"_ostr, 1);
+ OUString aValue = getXPath(pDoc, "/html/body/div[1]/div[1]/img"_ostr, "src"_ostr);
+ CPPUNIT_ASSERT(aValue.startsWith("data:image/svg+xml;base64"));
+}
+
+CPPUNIT_TEST_FIXTURE(XHtmlExportTest, testTdf131812)
+{
+ createSwDoc("tdf131812.odt");
+ setFilterOptions("UTF8");
+ save(mpFilter);
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ CPPUNIT_ASSERT(
+ aStream.indexOf(".paragraph-P1{ font-size:12pt; font-family:\'Liberation Serif\'; "
+ "writing-mode:horizontal-tb; direction:rtl; text-align:right ! important;}")
+ != -1);
+}
+
+CPPUNIT_TEST_FIXTURE(XHtmlExportTest, testTdf146264)
+{
+ createSwDoc("tdf146264.odt");
+ setFilterOptions("UTF8");
+ save(mpFilter);
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ sal_Int32 nFirstHello = aStream.indexOf("Hello");
+ CPPUNIT_ASSERT(nFirstHello > 0);
+ if (nFirstHello > 0)
+ {
+ sal_Int32 nSecondHello = aStream.indexOf("Hello", nFirstHello + 1);
+ constexpr sal_Int32 nMinusOne = -1;
+ CPPUNIT_ASSERT_EQUAL(nMinusOne, nSecondHello);
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(XHtmlExportTest, testTdf118637)
+{
+ createSwDoc("tdf118637.odt");
+ setFilterOptions("UTF8");
+ save(mpFilter);
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ CPPUNIT_ASSERT(aStream.indexOf("The formula  ") != -1);
+ CPPUNIT_ASSERT(aStream.indexOf("should be inline.</div>") != -1);
+}
+
+CPPUNIT_TEST_FIXTURE(XHtmlExportTest, testTdf145361)
+{
+ createSwDoc("tdf145361.odt");
+ setFilterOptions("UTF8");
+ save(mpFilter);
+ // Without the fix in place, this test would have failed with
+ // - SfxBaseModel::impl_store <file:///tmp/lu66091ameq.tmp> failed: 0xc10(Error Area:Io Class:Write Code:16)
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ CPPUNIT_ASSERT(
+ aStream.indexOf("List entry has<br/><span style=\"margin-left:0cm\"/>a line break") != -1);
+}
+
+CPPUNIT_TEST_FIXTURE(XHtmlExportTest, testTdf142483)
+{
+ createSwDoc("tdf142483.odt");
+ setFilterOptions("UTF8");
+ save(mpFilter);
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ CPPUNIT_ASSERT(
+ aStream.indexOf("padding:0.0382in; border-left-width:thin; border-left-style:solid; "
+ "border-left-color:#000000; border-right-style:none; "
+ "border-top-width:thin; border-top-style:solid; border-top-color:#000000; "
+ "border-bottom-width:thin; border-bottom-style:solid; "
+ "border-bottom-color:#000000;")
+ != -1);
+ CPPUNIT_ASSERT(
+ aStream.indexOf("padding:0.0382in; border-left-width:thin; border-left-style:solid; "
+ "border-left-color:#000000; border-right-style:none; "
+ "border-top-style:none; border-bottom-width:thin; "
+ "border-bottom-style:solid; border-bottom-color:#000000;")
+ != -1);
+ CPPUNIT_ASSERT(
+ aStream.indexOf("border-top-width:thin; border-top-style:solid; border-top-color:#000000; "
+ "border-left-width:thin; border-left-style:solid; "
+ "border-left-color:#000000; border-bottom-width:thin; "
+ "border-bottom-style:solid; border-bottom-color:#000000; "
+ "border-right-width:thin; border-right-style:solid; "
+ "border-right-color:#000000; padding:0.0382in;")
+ != -1);
+ CPPUNIT_ASSERT(
+ aStream.indexOf("padding:0.0382in; border-left-width:thin; border-left-style:solid; "
+ "border-left-color:#000000; border-right-width:thin; "
+ "border-right-style:solid; border-right-color:#000000; "
+ "border-top-style:none; border-bottom-width:thin; "
+ "border-bottom-style:solid; border-bottom-color:#000000;")
+ != -1);
+}
+
+CPPUNIT_TEST_FIXTURE(XHtmlExportTest, testTdf107696)
+{
+ createSwDoc("tdf107696.odt");
+ setFilterOptions("UTF8");
+ save(mpFilter);
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ //tdf#111492
+ CPPUNIT_ASSERT(aStream.indexOf("span.heading_numbering { margin-right: 0.8rem; }* { margin:0;}")
+ != -1);
+ CPPUNIT_ASSERT(
+ aStream.indexOf("<h2 class=\"paragraph-Heading_20_2\"><a "
+ "id=\"a__Level_2_without_number\"><span/></a>Level 2 without number</h2>")
+ != -1);
+ CPPUNIT_ASSERT(
+ aStream.indexOf(
+ "<h2 class=\"paragraph-Heading_20_2\"><a id=\"a_3_1_Level_2__number_3_1\"><span "
+ "class=\"heading_numbering\">3.1</span></a>Level <span "
+ "class=\"text-T2\">2</span>, <span class=\"text-T1\">number 3.1</span></h2>")
+ != -1);
+ CPPUNIT_ASSERT(
+ aStream.indexOf(
+ "<h2 class=\"paragraph-Heading_20_2\"><a id=\"a_3_2_Level_2__number_3_2\"><span "
+ "class=\"heading_numbering\">3.2</span></a>Level 2, <span "
+ "class=\"text-T1\">number 3.2</span></h2>")
+ != -1);
+}
+
+CPPUNIT_TEST_FIXTURE(XHtmlExportTest, testTdf66305)
+{
+ createSwDoc("tdf66305.odt");
+ setFilterOptions("UTF8");
+ save(mpFilter);
+ SvStream* pStream = maTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream);
+ sal_uInt64 nLength = pStream->TellEnd();
+ OString aStream(read_uInt8s_ToOString(*pStream, nLength));
+ CPPUNIT_ASSERT(
+ aStream.indexOf("<p class=\"paragraph-P6\"><a href=\"#__RefHeading__82004_486970805\" "
+ "class=\"text-Internet_20_link\">Introduction</a></p><p "
+ "class=\"paragraph-P7\"> </p>")
+ != -1);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */