Kaydet (Commit) 5c4d5021 authored tarafından Miklos Vajna's avatar Miklos Vajna

EPUB export: fix validation error on invalid relative links

It's valid to have a relative link that points nowhere in ODF, but the
same is not true for EPUB.

Change-Id: I7884032e277a0c53d0c513cea70dd2ee29ccd85c
üst cc2ee044
...@@ -85,6 +85,7 @@ public: ...@@ -85,6 +85,7 @@ public:
void testTableCellWidth(); void testTableCellWidth();
void testTableRowHeight(); void testTableRowHeight();
void testLink(); void testLink();
void testLinkInvalid();
void testLinkCharFormat(); void testLinkCharFormat();
void testLinkNamedCharFormat(); void testLinkNamedCharFormat();
void testTableWidth(); void testTableWidth();
...@@ -129,6 +130,7 @@ public: ...@@ -129,6 +130,7 @@ public:
CPPUNIT_TEST(testTableCellWidth); CPPUNIT_TEST(testTableCellWidth);
CPPUNIT_TEST(testTableRowHeight); CPPUNIT_TEST(testTableRowHeight);
CPPUNIT_TEST(testLink); CPPUNIT_TEST(testLink);
CPPUNIT_TEST(testLinkInvalid);
CPPUNIT_TEST(testLinkCharFormat); CPPUNIT_TEST(testLinkCharFormat);
CPPUNIT_TEST(testLinkNamedCharFormat); CPPUNIT_TEST(testLinkNamedCharFormat);
CPPUNIT_TEST(testTableWidth); CPPUNIT_TEST(testTableWidth);
...@@ -662,6 +664,15 @@ void EPUBExportTest::testLink() ...@@ -662,6 +664,15 @@ void EPUBExportTest::testLink()
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:a", "href", "https://libreoffice.org/"); assertXPath(mpXmlDoc, "//xhtml:p/xhtml:a", "href", "https://libreoffice.org/");
} }
void EPUBExportTest::testLinkInvalid()
{
createDoc("link-invalid.odt", {});
mpXmlDoc = parseExport("OEBPS/sections/section0001.xhtml");
// This was 1, invalid relative link was not filtered out.
assertXPath(mpXmlDoc, "//xhtml:p/xhtml:a", 0);
}
void EPUBExportTest::testLinkCharFormat() void EPUBExportTest::testLinkCharFormat()
{ {
createDoc("link-charformat.fodt", {}); createDoc("link-charformat.fodt", {});
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
</office:master-styles> </office:master-styles>
<office:body> <office:body>
<office:text> <office:text>
<text:p text:style-name="Standard"><draw:a xlink:type="simple" xlink:href="meta.cover-image.png"><draw:frame draw:style-name="fr1" draw:name="Image1" text:anchor-type="as-char" svg:width="1.806cm" svg:height="1.806cm" draw:z-index="0"><draw:image loext:mime-type="image/png"><office:binary-data>iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAABGdBTUEAALGPC/xhBQAAAAFz <text:p text:style-name="Standard"><draw:a xlink:type="simple" xlink:href="http://libreoffice.org/"><draw:frame draw:style-name="fr1" draw:name="Image1" text:anchor-type="as-char" svg:width="1.806cm" svg:height="1.806cm" draw:z-index="0"><draw:image loext:mime-type="image/png"><office:binary-data>iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAABGdBTUEAALGPC/xhBQAAAAFz
UkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA UkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA
AAJiS0dEAACqjSMyAAAACW9GRnMAAAAGAAAAAAAMc1XTAAAACXBIWXMAAA3XAAAN1wFCKJt4 AAJiS0dEAACqjSMyAAAACW9GRnMAAAAGAAAAAAAMc1XTAAAACXBIWXMAAA3XAAAN1wFCKJt4
AAAACXZwQWcAAABMAAAAQACdMTgbAAABzUlEQVRo3u3ZPU/CQBjA8X+Jxs3ESUDj4iK+LA5+ AAAACXZwQWcAAABMAAAAQACdMTgbAAABzUlEQVRo3u3ZPU/CQBjA8X+Jxs3ESUDj4iK+LA5+
......
...@@ -237,6 +237,7 @@ public: ...@@ -237,6 +237,7 @@ public:
private: private:
librevenge::RVNGPropertyList m_aPropertyList; librevenge::RVNGPropertyList m_aPropertyList;
PopupState m_ePopupState = PopupState::NONE;
}; };
XMLTextFrameHyperlinkContext::XMLTextFrameHyperlinkContext(XMLImport &rImport, const librevenge::RVNGPropertyList &rPropertyList) XMLTextFrameHyperlinkContext::XMLTextFrameHyperlinkContext(XMLImport &rImport, const librevenge::RVNGPropertyList &rPropertyList)
...@@ -265,8 +266,12 @@ void XMLTextFrameHyperlinkContext::startElement(const OUString &/*rName*/, const ...@@ -265,8 +266,12 @@ void XMLTextFrameHyperlinkContext::startElement(const OUString &/*rName*/, const
FillStyles(rAttributeValue, mrImport.GetAutomaticTextStyles(), mrImport.GetTextStyles(), m_aPropertyList); FillStyles(rAttributeValue, mrImport.GetAutomaticTextStyles(), mrImport.GetTextStyles(), m_aPropertyList);
else else
{ {
if (rAttributeName == "xlink:href" && mrImport.FillPopupData(rAttributeValue, aPropertyList)) if (rAttributeName == "xlink:href")
continue; {
m_ePopupState = mrImport.FillPopupData(rAttributeValue, aPropertyList);
if (m_ePopupState != PopupState::NotConsumed)
continue;
}
// This affects the link's properties. // This affects the link's properties.
OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8); OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8);
...@@ -275,12 +280,14 @@ void XMLTextFrameHyperlinkContext::startElement(const OUString &/*rName*/, const ...@@ -275,12 +280,14 @@ void XMLTextFrameHyperlinkContext::startElement(const OUString &/*rName*/, const
} }
} }
mrImport.GetGenerator().openLink(aPropertyList); if (m_ePopupState != PopupState::Ignore)
mrImport.GetGenerator().openLink(aPropertyList);
} }
void XMLTextFrameHyperlinkContext::endElement(const OUString &/*rName*/) void XMLTextFrameHyperlinkContext::endElement(const OUString &/*rName*/)
{ {
mrImport.GetGenerator().closeLink(); if (m_ePopupState != PopupState::Ignore)
mrImport.GetGenerator().closeLink();
} }
void XMLTextFrameHyperlinkContext::characters(const OUString &rChars) void XMLTextFrameHyperlinkContext::characters(const OUString &rChars)
...@@ -306,6 +313,7 @@ public: ...@@ -306,6 +313,7 @@ public:
private: private:
librevenge::RVNGPropertyList m_aPropertyList; librevenge::RVNGPropertyList m_aPropertyList;
PopupState m_ePopupState = PopupState::NONE;
}; };
XMLHyperlinkContext::XMLHyperlinkContext(XMLImport &rImport, const librevenge::RVNGPropertyList &rPropertyList) XMLHyperlinkContext::XMLHyperlinkContext(XMLImport &rImport, const librevenge::RVNGPropertyList &rPropertyList)
...@@ -334,8 +342,12 @@ void XMLHyperlinkContext::startElement(const OUString &/*rName*/, const css::uno ...@@ -334,8 +342,12 @@ void XMLHyperlinkContext::startElement(const OUString &/*rName*/, const css::uno
FillStyles(rAttributeValue, mrImport.GetAutomaticTextStyles(), mrImport.GetTextStyles(), m_aPropertyList); FillStyles(rAttributeValue, mrImport.GetAutomaticTextStyles(), mrImport.GetTextStyles(), m_aPropertyList);
else else
{ {
if (rAttributeName == "xlink:href" && mrImport.FillPopupData(rAttributeValue, aPropertyList)) if (rAttributeName == "xlink:href")
continue; {
m_ePopupState = mrImport.FillPopupData(rAttributeValue, aPropertyList);
if (m_ePopupState != PopupState::NotConsumed)
continue;
}
// This affects the link's properties. // This affects the link's properties.
OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8); OString sName = OUStringToOString(rAttributeName, RTL_TEXTENCODING_UTF8);
...@@ -344,12 +356,14 @@ void XMLHyperlinkContext::startElement(const OUString &/*rName*/, const css::uno ...@@ -344,12 +356,14 @@ void XMLHyperlinkContext::startElement(const OUString &/*rName*/, const css::uno
} }
} }
mrImport.GetGenerator().openLink(aPropertyList); if (m_ePopupState != PopupState::Ignore)
mrImport.GetGenerator().openLink(aPropertyList);
} }
void XMLHyperlinkContext::endElement(const OUString &/*rName*/) void XMLHyperlinkContext::endElement(const OUString &/*rName*/)
{ {
mrImport.GetGenerator().closeLink(); if (m_ePopupState != PopupState::Ignore)
mrImport.GetGenerator().closeLink();
} }
void XMLHyperlinkContext::characters(const OUString &rChars) void XMLHyperlinkContext::characters(const OUString &rChars)
......
...@@ -367,7 +367,7 @@ const librevenge::RVNGPropertyList &XMLImport::GetMetaData() ...@@ -367,7 +367,7 @@ const librevenge::RVNGPropertyList &XMLImport::GetMetaData()
return maMetaData; return maMetaData;
} }
bool XMLImport::FillPopupData(const OUString &rURL, librevenge::RVNGPropertyList &rPropList) PopupState XMLImport::FillPopupData(const OUString &rURL, librevenge::RVNGPropertyList &rPropList)
{ {
uno::Reference<uri::XUriReference> xUriRef; uno::Reference<uri::XUriReference> xUriRef;
try try
...@@ -378,32 +378,33 @@ bool XMLImport::FillPopupData(const OUString &rURL, librevenge::RVNGPropertyList ...@@ -378,32 +378,33 @@ bool XMLImport::FillPopupData(const OUString &rURL, librevenge::RVNGPropertyList
{ {
SAL_WARN("writerperfect", "XMLImport::FillPopupData: XUriReference::parse() failed:" << rException.Message); SAL_WARN("writerperfect", "XMLImport::FillPopupData: XUriReference::parse() failed:" << rException.Message);
} }
bool bRelative = false; bool bAbsolute = true;
if (xUriRef.is()) if (xUriRef.is())
bRelative = !xUriRef->isAbsolute(); bAbsolute = xUriRef->isAbsolute();
if (!bRelative) if (bAbsolute)
return false; return PopupState::NotConsumed;
OUString aAbs = maMediaDir + rURL; OUString aAbs = maMediaDir + rURL;
if (aAbs.isEmpty()) if (aAbs.isEmpty())
return false; return PopupState::NotConsumed;
SvFileStream aStream(aAbs, StreamMode::READ); SvFileStream aStream(aAbs, StreamMode::READ);
if (aStream.IsOpen()) if (!aStream.IsOpen())
{ // Relative link, but points to non-existing file: don't emit that to
librevenge::RVNGBinaryData aBinaryData; // librevenge, since it will be invalid anyway.
SvMemoryStream aMemoryStream; return PopupState::Ignore;
aMemoryStream.WriteStream(aStream);
aBinaryData.append(static_cast<const unsigned char *>(aMemoryStream.GetBuffer()), aMemoryStream.GetSize());
rPropList.insert("office:binary-data", aBinaryData);
INetURLObject aAbsURL(aAbs); librevenge::RVNGBinaryData aBinaryData;
OUString aMimeType = GetMimeType(aAbsURL.GetExtension()); SvMemoryStream aMemoryStream;
rPropList.insert("librevenge:mime-type", aMimeType.toUtf8().getStr()); aMemoryStream.WriteStream(aStream);
return true; aBinaryData.append(static_cast<const unsigned char *>(aMemoryStream.GetBuffer()), aMemoryStream.GetSize());
} rPropList.insert("office:binary-data", aBinaryData);
INetURLObject aAbsURL(aAbs);
OUString aMimeType = GetMimeType(aAbsURL.GetExtension());
rPropList.insert("librevenge:mime-type", aMimeType.toUtf8().getStr());
return false; return PopupState::Consumed;
} }
const std::vector<std::pair<uno::Sequence<sal_Int8>, Size>> &XMLImport::GetPageMetafiles() const const std::vector<std::pair<uno::Sequence<sal_Int8>, Size>> &XMLImport::GetPageMetafiles() const
......
...@@ -33,6 +33,19 @@ namespace exp ...@@ -33,6 +33,19 @@ namespace exp
class XMLImportContext; class XMLImportContext;
/// States describing the result of a link -> popup conversion.
enum class PopupState
{
/// Conversion did not happen yet.
NONE,
/// The relative link was converted to a popup.
Consumed,
/// The absolute link was not handled.
NotConsumed,
/// The relative link is invalid and should be ignored.
Ignore
};
/// ODT export feeds this class to make librevenge calls. /// ODT export feeds this class to make librevenge calls.
class XMLImport : public cppu::WeakImplHelper class XMLImport : public cppu::WeakImplHelper
< <
...@@ -85,7 +98,7 @@ public: ...@@ -85,7 +98,7 @@ public:
std::map<OUString, librevenge::RVNGPropertyList> &GetGraphicStyles(); std::map<OUString, librevenge::RVNGPropertyList> &GetGraphicStyles();
const librevenge::RVNGPropertyListVector &GetCoverImages(); const librevenge::RVNGPropertyListVector &GetCoverImages();
const librevenge::RVNGPropertyList &GetMetaData(); const librevenge::RVNGPropertyList &GetMetaData();
bool FillPopupData(const OUString &rURL, librevenge::RVNGPropertyList &rPropList); PopupState FillPopupData(const OUString &rURL, librevenge::RVNGPropertyList &rPropList);
const std::vector<std::pair<css::uno::Sequence<sal_Int8>, Size>> &GetPageMetafiles() const; const std::vector<std::pair<css::uno::Sequence<sal_Int8>, Size>> &GetPageMetafiles() const;
const css::uno::Reference<css::uno::XComponentContext> &GetComponentContext() const; const css::uno::Reference<css::uno::XComponentContext> &GetComponentContext() const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment