diff --git a/Common/3dParty/html/htmltoxhtml.h b/Common/3dParty/html/htmltoxhtml.h index 04dbdc22aa..71e78b520f 100644 --- a/Common/3dParty/html/htmltoxhtml.h +++ b/Common/3dParty/html/htmltoxhtml.h @@ -11,7 +11,6 @@ #include "../../../DesktopEditor/common/File.h" #include "../../../DesktopEditor/common/Directory.h" #include "../../../DesktopEditor/common/StringBuilder.h" -#include "../../../DesktopEditor/xml/include/xmlutils.h" #include "../../../UnicodeConverter/UnicodeConverter.h" #include "../../../HtmlFile2/src/StringFinder.h" diff --git a/HtmlFile2/Common.h b/HtmlFile2/Common.h new file mode 100644 index 0000000000..203d33d645 --- /dev/null +++ b/HtmlFile2/Common.h @@ -0,0 +1,37 @@ +#ifndef COMMON_H +#define COMMON_H + +#include + +namespace HTML +{ +void replace_all(std::wstring& s, const std::wstring& s1, const std::wstring& s2) +{ + size_t pos = s.find(s1); + size_t l = s2.length(); + while (pos != std::string::npos) + { + if (!(s1 == L"&" && s2 == L"&" && s.length() > pos + 4 && s[pos] == L'&' && s[pos + 1] == L'a' && s[pos + 2] == L'm' && s[pos + 3] == L'p' && s[pos + 4] == L';')) + s.replace(pos, s1.length(), s2); + pos = s.find(s1, pos + l); + } +} + +std::wstring EncodeXmlString(const std::wstring& s) +{ + std::wstring sRes = s; + + replace_all(sRes, L"&", L"&"); + replace_all(sRes, L"<", L"<"); + replace_all(sRes, L">", L">"); + replace_all(sRes, L"\"", L"""); + replace_all(sRes, L"\'", L"'"); + replace_all(sRes, L"\n", L" "); + replace_all(sRes, L"\r", L" "); + replace_all(sRes, L"\t", L" "); + + return sRes; +} +} + +#endif // COMMON_H diff --git a/HtmlFile2/HTML2OOXMLInterpretator.cpp b/HtmlFile2/HTML2OOXMLInterpretator.cpp new file mode 100644 index 0000000000..4b4d3b9c92 --- /dev/null +++ b/HtmlFile2/HTML2OOXMLInterpretator.cpp @@ -0,0 +1,342 @@ +#include "HTML2OOXMLInterpretator.h" + +#include "../DesktopEditor/common/File.h" +#include +#include + +namespace HTML +{ +inline bool ElementInTable(const std::vector& arSelectors); + +CHTML2OOXMLInterpretator::CHTML2OOXMLInterpretator() + : m_pCurrentDocument(&m_oDocXml), m_nFootnoteId(1), m_nHyperlinkId(1), m_nNumberingId(1), m_nId(1), m_nShapeId(1) +{} + +bool CHTML2OOXMLInterpretator::OpenP() +{ + if (m_oState.m_bInP) + return false; + + m_pCurrentDocument->WriteString(L""); + m_oState.m_bInP = true; + m_oState.m_bWasPStyle = false; + + return true; +} + +bool CHTML2OOXMLInterpretator::OpenR() +{ + if (m_oState.m_bInR) + return false; + + m_pCurrentDocument->WriteString(L""); + m_oState.m_bInR = true; + return true; +} + +bool CHTML2OOXMLInterpretator::OpenT() +{ + if (m_oState.m_bInT) + return false; + + m_pCurrentDocument->WriteString(L""); + m_oState.m_bInT = true; + return true; +} + +void CHTML2OOXMLInterpretator::CloseP(std::vector& arSelectors) +{ + m_oState.m_bWasSpace = true; + + if (!m_oState.m_bInP) + return; + + CloseT(); + CloseR(); + + if (m_oState.m_bInHyperlink) + { + if (arSelectors.rend() != std::find_if(arSelectors.rbegin(), arSelectors.rend(), [](const NSCSS::CNode& oNode) { return L"a" == oNode.m_wsName; })) + { + m_pCurrentDocument->WriteString(L""); + m_oState.m_bInHyperlink = false; + } + } + + m_pCurrentDocument->WriteString(L""); + m_oState.m_bInP = false; +} + +void CHTML2OOXMLInterpretator::CloseR() +{ + if (!m_oState.m_bInR) + return; + + m_pCurrentDocument->WriteString(L""); + m_oState.m_bInR = false; +} + +void CHTML2OOXMLInterpretator::CloseT() +{ + if (!m_oState.m_bInT) + return; + + m_pCurrentDocument->WriteString(L""); + m_oState.m_bInT = false; +} + +void CHTML2OOXMLInterpretator::OpenCrossHyperlink(const std::wstring& wsRef, std::vector& arSelectors, CTextSettings& oTS) +{ + if (!OpenP()) + CloseR(); + else + WritePPr(arSelectors, oTS); + + m_oState.m_bInHyperlink = true; + + m_pCurrentDocument->WriteString(L"WriteEncodeXmlString(AddAnchor(wsAnchorValue)); + + m_pCurrentDocument->WriteString(L"\">"); +} + +void CHTML2OOXMLInterpretator::OpenExternalHyperlink(const std::wstring& wsRef, const std::wstring& wsTooltip, std::vector& arSelectors, CTextSettings& oTS) +{ + if (!OpenP()) + CloseR(); + else + WritePPr(arSelectors, oTS); + + // Пишем рельсы + XmlString& oRelationshipXml(m_oDocXmlRels); + + if (*&m_pCurrentDocument == &m_oNoteXml) + oRelationshipXml = m_oNoteXmlRels; + + oRelationshipXml.WriteString(L""); + + m_oState.m_bInHyperlink = true; + // Пишем в document.xml + m_pCurrentDocument->WriteString(L"WriteEncodeXmlString(wsTooltip); + m_pCurrentDocument->WriteString(L"\" r:id=\"rHyp"); + m_pCurrentDocument->WriteString(std::to_wstring(m_nHyperlinkId++)); + m_pCurrentDocument->WriteString(L"\">"); +} + +void CHTML2OOXMLInterpretator::CloseCrossHyperlink(std::vector& arSelectors, std::wstring wsFootnote, const std::wstring& wsRef) +{ + if (!m_oState.m_bInP) + return; + + CloseExternalHyperlink(); + + bool bFootnote = false; + if (arSelectors.size() > 1) + { + const NSCSS::CNode& oNode = arSelectors[arSelectors.size() - 2]; + bFootnote = oNode.m_wsName == L"p" && oNode.m_wsClass == L"MsoFootnoteText"; + } + + // Сноска + if (!wsFootnote.empty()) + { + if (!bFootnote) + { + std::wstring sFootnoteID = std::to_wstring(m_nFootnoteId++); + OpenR(); + m_pCurrentDocument->WriteString(L"WriteString(sFootnoteID); + m_pCurrentDocument->WriteString(L"\"/>"); + CloseR(); + m_mFootnotes.insert(std::make_pair(wsFootnote, sFootnoteID)); + } + else + { + OpenR(); + m_pCurrentDocument->WriteString(L""); + CloseR(); + } + } +} + +void CHTML2OOXMLInterpretator::CloseExternalHyperlink() +{ + if (!m_oState.m_bInP && !m_oState.m_bInHyperlink) + return; + + CloseT(); + CloseR(); + m_pCurrentDocument->WriteString(L""); + m_oState.m_bInHyperlink = false; +} + +std::wstring CHTML2OOXMLInterpretator::WritePPr(std::vector& arSelectors, CTextSettings& oTS) +{ + OpenP(); + + if (m_oState.m_bWasPStyle) + return L""; + + std::wstring sPStyle = GetStyle(*arSelectors.back().m_pCompiledStyle, true); + + if (sPStyle.empty() && !ElementInTable(arSelectors)) + sPStyle = L"normal-web"; + + if (sPStyle.empty() && oTS.sPStyle.empty() && 0 > oTS.nLi) + return L""; + + m_oXmlStyle.WriteLitePStyle(oTS.oAdditionalStyle); + const std::wstring sPSettings = m_oXmlStyle.GetStyle(); + m_oXmlStyle.Clear(); + + m_pCurrentDocument->WriteNodeBegin(L"w:pPr"); + + if (!sPStyle.empty()) + { + m_pCurrentDocument->WriteString(L"WriteString(sPStyle); + m_pCurrentDocument->WriteString(L"\"/>"); + } + + if (oTS.nLi >= 0) + m_pCurrentDocument->WriteString(L""); + + m_pCurrentDocument->WriteString(oTS.sPStyle + sPSettings); + m_pCurrentDocument->WriteNodeEnd(L"w:pPr"); + m_oState.m_bWasPStyle = true; + + return sPStyle; +} + +void CHTML2OOXMLInterpretator::WriteEmptyParagraph(bool bVahish, bool bInP) +{ + if (!bInP) + m_pCurrentDocument->WriteString(L""); + + m_pCurrentDocument->WriteString(L""); + + if (bVahish) + m_pCurrentDocument->WriteString(L""); + + m_pCurrentDocument->WriteString(L""); + + if (!bInP) + m_pCurrentDocument->WriteString(L""); +} + +std::wstring CHTML2OOXMLInterpretator::WriteBookmark(const std::wstring& wsId) +{ + const std::wstring sCrossId = std::to_wstring(m_mBookmarks.size() + 1); + std::wstring sName; + + if (m_mBookmarks.end() != m_mBookmarks.find(wsId)) + sName = wsId + L"_" + std::to_wstring(++m_mBookmarks[wsId]); + else + { + const anchors_map::const_iterator itFound{m_mAnchors.find(wsId)}; + + if (m_mAnchors.end() != itFound) + sName = itFound->second; + else + sName = AddAnchor(wsId); + + m_mBookmarks.insert({wsId, 1}); + } + + m_pCurrentDocument->WriteString(L"WriteString(sCrossId); + m_pCurrentDocument->WriteString(L"\" w:name=\""); + m_pCurrentDocument->WriteEncodeXmlString(sName); + m_pCurrentDocument->WriteString(L"\"/>"); + + return sCrossId; +} + +std::wstring CHTML2OOXMLInterpretator::AddAnchor(const std::wstring& wsAnchorValue) +{ + const anchors_map::iterator itFound = m_mAnchors.find(wsAnchorValue); + + if (m_mAnchors.end() != itFound) + return itFound->second; + + const std::wstring wsAnchorId{L"anchor-" + std::to_wstring(m_mAnchors.size() + 1)}; + m_mAnchors[wsAnchorValue] = wsAnchorId; + + return wsAnchorId; +} + +std::wstring CHTML2OOXMLInterpretator::GetStyle(const NSCSS::CCompiledStyle& oStyle, bool bParagraphStyle) +{ + if ((bParagraphStyle && !m_oXmlStyle.WritePStyle(oStyle)) || (!bParagraphStyle && !m_oXmlStyle.WriteRStyle(oStyle))) + return L""; + + m_oStylesXml.WriteString(m_oXmlStyle.GetStyle()); + return m_oXmlStyle.GetIdAndClear(); +} + +XmlString& CHTML2OOXMLInterpretator::GetStylesXml() +{ + return m_oStylesXml; +} + +XmlString& CHTML2OOXMLInterpretator::GetDocRelsXml() +{ + return m_oDocXmlRels; +} + +XmlString& CHTML2OOXMLInterpretator::GetNotesRelsXml() +{ + return m_oNoteXmlRels; +} + +XmlString& CHTML2OOXMLInterpretator::GetDocumentXml() +{ + return m_oDocXml; +} + +XmlString& CHTML2OOXMLInterpretator::GetNotesXml() +{ + return m_oNoteXml; +} + +XmlString& CHTML2OOXMLInterpretator::GetNumberingXml() +{ + return m_oNumberXml; +} + +XmlString& CHTML2OOXMLInterpretator::GetWebSettingsXml() +{ + return m_oWebSettings; +} + +XmlString& CHTML2OOXMLInterpretator::GetCurrentDocument() +{ + return *m_pCurrentDocument; +} + +void CHTML2OOXMLInterpretator::PrintData() +{ + std::wcout << m_oDocXml.GetData() << std::endl; +} + +inline bool ElementInTable(const std::vector& arSelectors) +{ + return arSelectors.crend() != std::find_if(arSelectors.crbegin(), arSelectors.crend(), [](const NSCSS::CNode& oNode) { return L"table" == oNode.m_wsName; }); +} +} diff --git a/HtmlFile2/HTML2OOXMLInterpretator.h b/HtmlFile2/HTML2OOXMLInterpretator.h new file mode 100644 index 0000000000..881549007b --- /dev/null +++ b/HtmlFile2/HTML2OOXMLInterpretator.h @@ -0,0 +1,101 @@ +#ifndef HTML2OOXMLINTERPRETATOR_H +#define HTML2OOXMLINTERPRETATOR_H + +// #include "HTMLInterpretator.h" +#include "../DesktopEditor/common/StringBuilder.h" + +#include "../Common/3dParty/html/css/src/xhtml/CDocumentStyle.h" +#include "../Common/3dParty/html/css/src/CNode.h" +#include "../TextSettings.h" +#include "HTMLInterpretator.h" + +namespace HTML +{ +using XmlString = NSStringUtils::CStringBuilder; + +class CHTML2OOXMLInterpretator : public IHTMLInterpretator +{ + XmlString m_oStylesXml; // styles.xml + XmlString m_oDocXmlRels; // document.xml.rels + XmlString m_oNoteXmlRels; // footnotes.xml.rels + XmlString m_oDocXml; // document.xml + XmlString m_oNoteXml; // footnotes.xml + XmlString m_oNumberXml; // numbering.xml + XmlString m_oWebSettings; // webSettings.xml + + XmlString *m_pCurrentDocument; //Текущее место записи + + NSCSS::CDocumentStyle m_oXmlStyle; // Ooxml стиль + + struct TState + { + bool m_bInP; // открыт? + bool m_bInR; // открыт? + bool m_bInT; // открыт? + bool m_bWasPStyle; // записан? + bool m_bWasSpace; // Был пробел? + bool m_bInHyperlink; // открыт? + + bool m_bBanUpdatePageData; // Запретить обновление данных о странице? + + std::wstring m_wsNote; + + // HtmlTag m_eLastElement; + + TState() + : m_bInP(false), m_bInR(false), m_bInT(false), m_bWasPStyle(false), m_bWasSpace(true), m_bInHyperlink(false), m_bBanUpdatePageData(false)/*, m_eLastElement(HTML_TAG(UNKNOWN))*/ + {} + } m_oState; + + int m_nFootnoteId; // ID сноски + int m_nHyperlinkId; // ID ссылки + int m_nNumberingId; // ID списка + int m_nId; // ID остальные элементы + int m_nShapeId; // Id shape's + + std::map m_mFootnotes; // Сноски + std::map m_mBookmarks; // Закладки + using anchors_map = std::map; + anchors_map m_mAnchors; // Map якорей с индивидуальными id +public: + CHTML2OOXMLInterpretator(); + + bool OpenP(); + bool OpenR(); + bool OpenT(); + + void CloseP(std::vector& sSelectors); + void CloseR(); + void CloseT(); + + void OpenCrossHyperlink(const std::wstring& wsRef, std::vector& arSelectors, CTextSettings& oTS); + void OpenExternalHyperlink(const std::wstring& wsRef, const std::wstring& wsTooltip, std::vector& arSelectors, CTextSettings& oTS); + + void CloseCrossHyperlink(std::vector& arSelectors, std::wstring wsFootnote, const std::wstring& wsRef); + void CloseExternalHyperlink(); + + std::wstring WritePPr(std::vector& arSelectors, CTextSettings& oTS); + + void WriteEmptyParagraph(bool bVahish = false, bool bInP = false) override; + + std::wstring WriteBookmark(const std::wstring& wsId); + std::wstring AddAnchor(const std::wstring& wsAnchorValue); + + std::wstring GetStyle(const NSCSS::CCompiledStyle& oStyle, bool bParagraphStyle); + + XmlString& GetStylesXml(); + XmlString& GetDocRelsXml(); + XmlString& GetNotesRelsXml(); + XmlString& GetDocumentXml(); + XmlString& GetNotesXml(); + XmlString& GetNumberingXml(); + XmlString& GetWebSettingsXml(); + XmlString& GetCurrentDocument(); + + #ifdef _DEBUG + virtual void PrintData() override; + #endif +}; +} + +#endif // HTML2OOXMLINTERPRETATOR_H diff --git a/HtmlFile2/HTMLInterpretator.h b/HtmlFile2/HTMLInterpretator.h new file mode 100644 index 0000000000..b54fe19f50 --- /dev/null +++ b/HtmlFile2/HTMLInterpretator.h @@ -0,0 +1,58 @@ +#ifndef HTMLINTERPRETATOR_H +#define HTMLINTERPRETATOR_H + +namespace HTML +{ +class IHTMLInterpretator +{ +public: + IHTMLInterpretator() = default; + virtual ~IHTMLInterpretator() = default; + + virtual void WriteEmptyParagraph(bool bVahish = false, bool bInP = false) = 0; + + #ifdef _DEBUG + virtual void PrintData() = 0; + #endif + + // virtual bool ReadText(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadA(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadAbbr(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadBold(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadBdo(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadBdi(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadBr(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadCenter(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadItalic(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadCode(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadKbd(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadSamp(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadStrike(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadFont(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool readImage(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadUnderline(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadMark(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadQ(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadSup(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadSub(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool readSVG(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool readInput(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadSpan(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadNobr(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadBasefont(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadDD(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadDiv(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadBlockquote(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadHr(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadListElement(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadList(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool readMenu(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadPre(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadTable(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadRuby(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadTextarea(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; + // virtual bool ReadDetails(NSStringUtils::CStringBuilder& oXml, std::vector& sSelectors, TTextSettings& oTS) = 0; +}; +} + +#endif // HTMLINTERPRETATOR_H diff --git a/HtmlFile2/HTMLReader.cpp b/HtmlFile2/HTMLReader.cpp new file mode 100644 index 0000000000..e0aeab33bb --- /dev/null +++ b/HtmlFile2/HTMLReader.cpp @@ -0,0 +1,881 @@ +#include "HTMLReader.h" + +#include "../Common/Network/FileTransporter/include/FileTransporter.h" +#include "../DesktopEditor/common/File.h" +#include "../DesktopEditor/common/Path.h" + +#include "Common.h" +#include "Tags/HTMLTags2OOXML.h" +#include "../Common/3dParty/html/gumbo-parser/src/gumbo.h" +#include +#include + +namespace HTML +{ +#define HTML_TAG(tag) GUMBO_TAG_##tag +#define ADD_TAG(strName, enumName) {strName, HTML_TAG(enumName)} +#define SKIP_TAG SCRIPT +#define UNKNOWN_TAG GumboTag::GUMBO_TAG_UNKNOWN + +#define HtmlTag GumboTag + +const std::map m_HTML_TAGS +{ + ADD_TAG(L"a", A), + ADD_TAG(L"abbr", ABBR), + ADD_TAG(L"acronym", ACRONYM), + ADD_TAG(L"address", ADDRESS), + ADD_TAG(L"applet", APPLET), + ADD_TAG(L"area", AREA), + ADD_TAG(L"article", ARTICLE), + ADD_TAG(L"aside", ASIDE), + ADD_TAG(L"audio", AUDIO), + ADD_TAG(L"b", B), + ADD_TAG(L"base", BASE), + ADD_TAG(L"basefont", BASEFONT), + ADD_TAG(L"bdi", BDI), + ADD_TAG(L"bdo", BDO), + ADD_TAG(L"bgsound", BGSOUND), + ADD_TAG(L"blockquote", BLOCKQUOTE), + ADD_TAG(L"big", BIG), + ADD_TAG(L"body", BODY), + ADD_TAG(L"blink", BLINK), + ADD_TAG(L"br", BR), + ADD_TAG(L"button", BUTTON), + ADD_TAG(L"canvas", CANVAS), + ADD_TAG(L"caption", CAPTION), + ADD_TAG(L"center", CENTER), + ADD_TAG(L"cite", CITE), + ADD_TAG(L"code", CODE), + ADD_TAG(L"col", COL), + ADD_TAG(L"colgroup", COLGROUP), + ADD_TAG(L"command", SKIP_TAG), // Данного обозначения нет, но т.к.мы всё равно пропускаем, то делаем script + ADD_TAG(L"comment", SKIP_TAG), // Данного обозначения нет, но т.к.мы всё равно пропускаем, то делаем script + ADD_TAG(L"datalist", DATALIST), + ADD_TAG(L"dd", DD), + ADD_TAG(L"del", DEL), + ADD_TAG(L"details", DETAILS), + ADD_TAG(L"dfn", DFN), + ADD_TAG(L"dir", DIR), + ADD_TAG(L"div", DIV), + ADD_TAG(L"dl", DL), + ADD_TAG(L"dt", DT), + ADD_TAG(L"em", EM), + ADD_TAG(L"embed", EMBED), + ADD_TAG(L"fieldset", FIELDSET), + ADD_TAG(L"figcaption", FIGCAPTION), + ADD_TAG(L"figure", FIGURE), + ADD_TAG(L"font", FONT), + ADD_TAG(L"form", FORM), + ADD_TAG(L"footer", FOOTER), + ADD_TAG(L"frame", FRAME), + ADD_TAG(L"frameset", FRAMESET), + ADD_TAG(L"h1", H1), + ADD_TAG(L"h2", H2), + ADD_TAG(L"h3", H3), + ADD_TAG(L"h4", H4), + ADD_TAG(L"h5", H5), + ADD_TAG(L"h6", H6), + ADD_TAG(L"head", HEAD), + ADD_TAG(L"header", HEADER), + ADD_TAG(L"hgroup", HGROUP), + ADD_TAG(L"hr", HR), + ADD_TAG(L"html", HTML), + ADD_TAG(L"i", I), + ADD_TAG(L"iframe", IFRAME), + ADD_TAG(L"img", IMG), + ADD_TAG(L"input", INPUT), + ADD_TAG(L"ins", INS), + ADD_TAG(L"isindex", ISINDEX), + ADD_TAG(L"kbd", KBD), + ADD_TAG(L"keygen", KEYGEN), + ADD_TAG(L"label", LABEL), + ADD_TAG(L"legend", LEGEND), + ADD_TAG(L"li", LI), + ADD_TAG(L"link", LINK), + ADD_TAG(L"main", MAIN), + ADD_TAG(L"map", MAP), + ADD_TAG(L"marquee", MARQUEE), + ADD_TAG(L"mark", MARK), + ADD_TAG(L"menu", MENU), + ADD_TAG(L"meta", META), + ADD_TAG(L"meter", METER), + ADD_TAG(L"nav", NAV), + ADD_TAG(L"nobr", NOBR), + ADD_TAG(L"noembed", NOEMBED), + ADD_TAG(L"noframes", NOFRAMES), + ADD_TAG(L"noscript", NOSCRIPT), + ADD_TAG(L"object", OBJECT), + ADD_TAG(L"ol", OL), + ADD_TAG(L"optgroup", OPTGROUP), + ADD_TAG(L"option", OPTION), + ADD_TAG(L"output", OUTPUT), + ADD_TAG(L"p", P), + ADD_TAG(L"param", PARAM), + ADD_TAG(L"plaintext", PLAINTEXT), + ADD_TAG(L"pre", PRE), + ADD_TAG(L"progress", PROGRESS), + ADD_TAG(L"q", Q), + ADD_TAG(L"rp", RP), + ADD_TAG(L"rt", RT), + ADD_TAG(L"ruby", RUBY), + ADD_TAG(L"s", S), + ADD_TAG(L"samp", SAMP), + ADD_TAG(L"script", SCRIPT), + ADD_TAG(L"section", SECTION), + ADD_TAG(L"select", SELECT), + ADD_TAG(L"small", SMALL), + ADD_TAG(L"span", SPAN), + ADD_TAG(L"source", SOURCE), + ADD_TAG(L"strike", STRIKE), + ADD_TAG(L"strong", STRONG), + ADD_TAG(L"style", STYLE), + ADD_TAG(L"sub", SUB), + ADD_TAG(L"summary", SUMMARY), + ADD_TAG(L"sup", SUP), + ADD_TAG(L"table", TABLE), + ADD_TAG(L"tbody", TBODY), + ADD_TAG(L"td", TD), + ADD_TAG(L"textarea", TEXTAREA), + ADD_TAG(L"tfoot", TFOOT), + ADD_TAG(L"th", TH), + ADD_TAG(L"thead", THEAD), + ADD_TAG(L"time", TIME), + ADD_TAG(L"title", TITLE), + ADD_TAG(L"tr", TR), + ADD_TAG(L"tt", TT), + ADD_TAG(L"u", U), + ADD_TAG(L"ul", UL), + ADD_TAG(L"var", VAR), + ADD_TAG(L"video", VIDEO), + ADD_TAG(L"wbr", WBR), + ADD_TAG(L"xmp", XMP), + + ADD_TAG(L"svg", SVG) +}; +inline std::wstring GetArgumentValue(XmlUtils::CXmlLiteReader& oLiteReader, const std::wstring& wsArgumentName, const std::wstring& wsDefaultValue = L""); +inline bool CheckArgumentMath(const std::wstring& wsNodeName, const std::wstring& wsStyleName); +inline HtmlTag GetHtmlTag(const std::wstring& wsStrTag); +inline bool UnreadableNode(const std::wstring& wsNodeName); +inline bool TagIsUnprocessed(const std::wstring& wsTagName); + +CHTMLReader::CHTMLReader() + : m_pInterpretator(new CHTML2OOXMLInterpretator()) +{ + m_mTags[HTML_TAG(A)] = new TAnchor((CHTML2OOXMLInterpretator*)m_pInterpretator); +} + +CHTMLReader::~CHTMLReader() +{ + if (nullptr != m_pInterpretator) + delete m_pInterpretator; +} + +HRESULT CHTMLReader::ReadFromFile(const std::wstring& wsFileName) +{ + if (!HTML2XHTML(wsFileName) || !m_oLightReader.IsValid() || !IsHTML()) + return S_FALSE; + + m_sSrc = NSSystemPath::GetDirectoryName(wsFileName); + // m_sDst = sDst; + + ReadStyle(); + + // Переходим в начало + if(!m_oLightReader.MoveToStart()) + return S_FALSE; + + // if(oParams && oParams->m_bNeedPageBreakBefore) + // m_internal->PageBreakBefore(); + + ReadDocument(); + return S_OK; +} + +bool CHTMLReader::IsHTML() +{ + return ((m_oLightReader.MoveToStart() && m_oLightReader.ReadNextNode()) ? m_oLightReader.GetName() == L"html" : false) && m_oLightReader.MoveToStart(); +} + +bool CHTMLReader::HTML2XHTML(const std::wstring& wsFileName) +{ + BYTE* pData; + DWORD nLength; + if (!NSFile::CFileBinary::ReadAllBytes(wsFileName, &pData, nLength)) + return false; + + std::string sFileContent = XmlUtils::GetUtf8FromFileContent(pData, nLength); + + bool bNeedConvert = true; + if (nLength > 4) + { + if (pData[0] == 0xFF && pData[1] == 0xFE && !(pData[2] == 0x00 && pData[3] == 0x00)) + bNeedConvert = false; + if (pData[0] == 0xFE && pData[1] == 0xFF) + bNeedConvert = false; + + if (pData[0] == 0xFF && pData[1] == 0xFE && pData[2] == 0x00 && pData[3] == 0x00) + bNeedConvert = false; + if (pData[0] == 0 && pData[1] == 0 && pData[2] == 0xFE && pData[3] == 0xFF) + bNeedConvert = false; + } + + RELEASEARRAYOBJECTS(pData); + + size_t nFind = sFileContent.find("version=\""); + if(nFind != std::string::npos) + { + nFind += 9; + size_t nFindEnd = sFileContent.find("\"", nFind); + if(nFindEnd != std::string::npos) + sFileContent.replace(nFind, nFindEnd - nFind, "1.0"); + } + + // const std::wstring sRes{htmlToXhtml(sFileContent, bNeedConvert)}; + + #ifdef SAVE_NORMALIZED_HTML + #if 1 == SAVE_NORMALIZED_HTML + NSFile::CFileBinary oWriter; + if (oWriter.CreateFileW(m_sTmp + L"/res.html")) + { + oWriter.WriteStringUTF8(sRes); + oWriter.CloseFile(); + } + #endif + #endif + + return m_oLightReader.FromString(UTF8_TO_U(sFileContent)); +} + +void CHTMLReader::ReadStyle() +{ + if(m_oLightReader.IsEmptyNode()) + return; + + const int nDeath = m_oLightReader.GetDepth(); + std::wstring sName; + + while(m_oLightReader.ReadNextSiblingNode(nDeath)) + { + sName = m_oLightReader.GetName(); + + if(sName == L"body") + ReadStyle2(); + else + { + // Стиль по ссылке + if(sName == L"link") + { + while(m_oLightReader.MoveToNextAttribute()) + ReadStyleFromNetwork(); + + m_oLightReader.MoveToElement(); + } + // тэг style содержит стили для styles.xml + else if(sName == L"style") + m_oStylesCalculator.AddStyles(m_oLightReader.GetText2()); + else + ReadStyle(); + } + } +} + +void CHTMLReader::ReadStyle2() +{ + std::wstring sName = m_oLightReader.GetName(); + // Стиль по ссылке + if(sName == L"link") + { + while(m_oLightReader.MoveToNextAttribute()) + ReadStyleFromNetwork(); + m_oLightReader.MoveToElement(); + } + // тэг style содержит стили для styles.xml + else if(sName == L"style") + m_oStylesCalculator.AddStyles(m_oLightReader.GetText2()); + + const int nDeath = m_oLightReader.GetDepth(); + while(m_oLightReader.ReadNextSiblingNode(nDeath)) + { + if(!m_oLightReader.IsEmptyNode()) + ReadStyle2(); + } +} + +void CHTMLReader::ReadStyleFromNetwork() +{ + if(m_oLightReader.GetName() != L"href") + return; + std::wstring sRef = m_oLightReader.GetText(); + if(NSFile::GetFileExtention(sRef) != L"css") + return; + std::wstring sFName = NSFile::GetFileName(sRef); + // Стиль в сети + if(sRef.substr(0, 4) == L"http") + { + sFName = m_sTmp + L'/' + sFName; + NSNetwork::NSFileTransport::CFileDownloader oDownloadStyle(sRef, false); + oDownloadStyle.SetFilePath(sFName); + if(oDownloadStyle.DownloadSync()) + { + m_oStylesCalculator.AddStylesFromFile(sFName); + NSFile::CFileBinary::Remove(sFName); + } + } + else + { + m_oStylesCalculator.AddStylesFromFile(m_sSrc + L'/' + sFName); + m_oStylesCalculator.AddStylesFromFile(m_sSrc + L'/' + sRef); + } +} + +void CHTMLReader::ReadDocument() +{ + m_oLightReader.ReadNextNode(); + + int nDeath = m_oLightReader.GetDepth(); + while(m_oLightReader.ReadNextSiblingNode(nDeath)) + { + std::wstring sName = m_oLightReader.GetName(); + if(sName == L"head") + ReadHead(); + else if(sName == L"body") + ReadBody(); + } +} + +void CHTMLReader::ReadHead() +{ + if(m_oLightReader.IsEmptyNode()) + return; + int nDeath = m_oLightReader.GetDepth(); + while (m_oLightReader.ReadNextSiblingNode(nDeath)) + { + const std::wstring wsName = m_oLightReader.GetName(); + // Базовый адрес + if (L"base" == wsName) + m_sBase = GetArgumentValue(m_oLightReader, L"href"); + } + + m_oLightReader.MoveToElement(); +} + +void CHTMLReader::ReadBody() +{ + std::vector arSelectors; + + arSelectors.push_back(NSCSS::CNode(L"html", L"", L"")); + + GetSubClass(arSelectors); + + /* + if (!sSelectors.back().m_mAttributes.empty()) + { + std::map::iterator itFound = sSelectors.back().m_mAttributes.find(L"bgcolor"); + + if (sSelectors.back().m_mAttributes.end() != itFound) + { + NSCSS::NSProperties::CColor oColor; + oColor.SetValue(itFound->second); + + if (!oColor.Empty() && !oColor.None()) + { + const std::wstring wsHEXColor{oColor.ToHEX()}; + + if (!wsHEXColor.empty()) + m_oDocXml.WriteString(L""); + + sSelectors.back().m_mAttributes.erase(itFound); + } + } + } + + m_oLightReader.MoveToElement(); + */ + + CTextSettings oTS; + ReadStream(arSelectors, oTS); +} + +bool CHTMLReader::ReadStream(std::vector& arSelectors, CTextSettings& oTS, bool bInsertEmptyP) +{ + int nDeath = m_oLightReader.GetDepth(); + if(m_oLightReader.IsEmptyNode() || !m_oLightReader.ReadNextSiblingNode2(nDeath)) + { + if (bInsertEmptyP) + m_pInterpretator->WriteEmptyParagraph(true, true); + // WriteEmptyParagraph(sSelectors, oTS); + return false; + // WriteEmptyParagraph(sSelectors, oTS); + // if (bInsertEmptyP) + // { + // wrP(oXml, sSelectors, oTS); + // wrRPr(oXml, sSelectors, oTS); + // CloseP(oXml, sSelectors); + // m_oState.m_bInP = false; + + // return true; + // } + } + + bool bResult = false; + + do + { + if (ReadInside(arSelectors, oTS)) + bResult = true; + } while(m_oLightReader.ReadNextSiblingNode2(nDeath)); + + if (!bResult && bInsertEmptyP) + m_pInterpretator->WriteEmptyParagraph(true, true); + // WriteEmptyParagraph(sSelectors, oTS); + + // if (!bResult && bInsertEmptyP) + // { + // wrP(oXml, sSelectors, oTS); + // wrRPr(oXml, sSelectors, oTS); + // CloseP(oXml, sSelectors); + // m_oState.m_bInP = false; + // } + + return bResult; +} + +bool CHTMLReader::ReadInside(std::vector& arSelectors, CTextSettings& oTS) +{ + const std::wstring wsName{m_oLightReader.GetName()}; + + //TODO:: обработать все варианты return'а + // if(wsName == L"#text") + // return m_pInterpretator->ReadText(oXml, arSelectors, oTS); + + if (UnreadableNode(wsName) || TagIsUnprocessed(wsName)) + return false; + + GetSubClass(arSelectors); + + bool bResult = true; + + const HtmlTag eHtmlTag{GetHtmlTag(wsName)}; + + switch(eHtmlTag) + { + case HTML_TAG(A): + case HTML_TAG(AREA): + { + bResult = ReadA(arSelectors, oTS); + break; + } + default: + break; + // case HTML_TAG(ABBR): + // { + // bResult = m_pInterpretator->ReadAbbr(oXml, arSelectors, oTS, sNote); + // break; + // } + // case HTML_TAG(B): + // case HTML_TAG(STRONG): + // { + // bResult = m_pInterpretator->ReadBold(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(BDO): + // { + // bResult = m_pInterpretator->ReadBdo(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(BDI): + // { + // bResult = m_pInterpretator->ReadBdi(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(BR): + // { + // bResult = m_pInterpretator->ReadBr(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(CENTER): + // { + // bResult = m_pInterpretator->ReadCenter(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(CITE): + // case HTML_TAG(DFN): + // case HTML_TAG(EM): + // case HTML_TAG(I): + // case HTML_TAG(VAR): + // { + // bResult = m_pInterpretator->ReadItalic(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(CODE): + // case HTML_TAG(TT): + // { + // bResult = m_pInterpretator->ReadCode(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(KBD): + // { + // bResult = m_pInterpretator->ReadKbd(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(SAMP): + // { + // bResult = m_pInterpretator->ReadSamp(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(DEL): + // case HTML_TAG(S): + // case HTML_TAG(STRIKE): + // { + // bResult = m_pInterpretator->ReadStrike(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(FONT): + // { + // bResult = m_pInterpretator->ReadFont(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(IMG): + // { + // bResult = m_pInterpretator->readImage(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(INS): + // case HTML_TAG(U): + // { + // bResult = m_pInterpretator->ReadUnderline(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(MARK): + // { + // bResult = m_pInterpretator->ReadMark(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(Q): + // { + // bResult = m_pInterpretator->ReadQ(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(SUP): + // { + // bResult = m_pInterpretator->ReadSup(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(SUB): + // { + // bResult = m_pInterpretator->ReadSub(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(SVG): + // { + // m_pInterpretator->readSVG(oXml, sSelectors, oTS); + + // wrP(oXml, sSelectors, oTS); + // bResult = readSVG(m_oLightReader.GetOuterXml()); + + // if (bResult) + // ImageRels(oXml, -1, L"", L"png"); + + // break; + // } + // case HTML_TAG(INPUT): + // { + // bResult = readInput(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(CANVAS): + // case HTML_TAG(VIDEO): + // case HTML_TAG(MATH): + // case HTML_TAG(IFRAME): + // case HTML_TAG(EMBED): + // case HTML_TAG(WBR): + // case HTML_TAG(AUDIO): + // case HTML_TAG(BGSOUND): + // case HTML_TAG(APPLET): + // case HTML_TAG(BLINK): + // case HTML_TAG(KEYGEN): + // case HTML_TAG(TITLE): + // case HTML_TAG(STYLE): + // case HTML_TAG(SCRIPT): + // { + // //Если встретили не обрабатываемые теги, то просто пропускаем + // sSelectors.pop_back(); + // return false; + // } + // case HTML_TAG(SPAN): + // { + // bResult = ReadSpan(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(NOBR): + // { + // bResult = ReadNobr(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(BASEFONT): + // { + // bResult = ReadBasefont(oXml, sSelectors, oTS); + // break; + // } + // case HTML_TAG(BUTTON): + // case HTML_TAG(LABEL): + // case HTML_TAG(DATA): + // case HTML_TAG(OBJECT): + // case HTML_TAG(NOSCRIPT): + // case HTML_TAG(OUTPUT): + // case HTML_TAG(TIME): + // case HTML_TAG(SMALL): + // case HTML_TAG(PROGRESS): + // case HTML_TAG(HGROUP): + // case HTML_TAG(METER): + // case HTML_TAG(ACRONYM): + // case HTML_TAG(BIG): + // { + // bResult = eadStream(sSelectors, oTS); + // break; + // } + // default: + // { + // NSStringUtils::CStringBuilder oXmlData; + // TState oCurentState{m_oState}; + + // CloseP(&oXmlData, sSelectors); + + // switch(eHtmlTag) + // { + // case HTML_TAG(ADDRESS): + // { + // bResult = ReadItalic(&oXmlData, sSelectors, oTS); + // break; + // } + // case HTML_TAG(DD): + // { + // bResult = ReadDD(&oXmlData, sSelectors, oTS); + // break; + // } + // case HTML_TAG(ASIDE): + // case HTML_TAG(DIV): + // { + // bResult = ReadDiv(&oXmlData, sSelectors, oTS); + // break; + // } + // case HTML_TAG(BLOCKQUOTE): + // { + // bResult = ReadBlockquote(&oXmlData, sSelectors, oTS); + // break; + // } + // case HTML_TAG(ARTICLE): + // case HTML_TAG(HEADER): + // case HTML_TAG(MAIN): + // case HTML_TAG(SUMMARY): + // case HTML_TAG(FOOTER): + // case HTML_TAG(NAV): + // case HTML_TAG(FIGCAPTION): + // case HTML_TAG(FORM): + // case HTML_TAG(OPTION): + // case HTML_TAG(DT): + // case HTML_TAG(P): + // case HTML_TAG(SECTION): + // case HTML_TAG(FIGURE): + // case HTML_TAG(DL): + // case HTML_TAG(LEGEND): + // case HTML_TAG(MAP): + // case HTML_TAG(H1): + // case HTML_TAG(H2): + // case HTML_TAG(H3): + // case HTML_TAG(H4): + // case HTML_TAG(H5): + // case HTML_TAG(H6): + // { + // bResult = readStream(&oXmlData, sSelectors, oTS); + // break; + // } + // case HTML_TAG(HR): + // { + // bResult = ReadHr(&oXmlData, sSelectors, oTS); + // break; + // } + // case HTML_TAG(LI): + // { + // bResult = ReadListElement(&oXmlData, sSelectors, oTS); + // break; + // } + // case HTML_TAG(OL): + // case HTML_TAG(UL): + // { + // bResult = ReadList(&oXmlData, sSelectors, oTS); + // break; + // } + // case HTML_TAG(MENU): + // case HTML_TAG(SELECT): + // case HTML_TAG(DATALIST): + // case HTML_TAG(DIR): + // { + // bResult = readLi(&oXmlData, sSelectors, oTS, HTML_TAG(OL) != eHtmlTag); + // break; + // } + // case HTML_TAG(PRE): + // case HTML_TAG(XMP): + // { + // bResult = ReadPre(&oXmlData, sSelectors, oTS); + // break; + // } + // case HTML_TAG(TABLE): + // { + // bResult = ParseTable(&oXmlData, sSelectors, oTS); + // break; + // } + // case HTML_TAG(RUBY): + // { + // bResult = ParseRuby(&oXmlData, sSelectors, oTS); + // break; + // } + // case HTML_TAG(TEXTAREA): + // case HTML_TAG(FIELDSET): + // { + // bResult = ReadTextarea(&oXmlData, sSelectors, oTS); + // break; + // } + // case HTML_TAG(DETAILS): + // { + // bResult = ReadDetails(&oXmlData, sSelectors, oTS); + // break; + // } + // default: + // { + // bResult = readStream(&oXmlData, sSelectors, oTS); + // break; + // } + // } + + // readNote(&oXmlData, sSelectors, sNote); + + // CloseP(&oXmlData, sSelectors); + + // if (bResult) + // WriteToStringBuilder(oXmlData, *oXml); + // else + // m_oState = oCurentState; + // } + } + + // if (HTML_TAG(DIV) != eHtmlTag && HTML_TAG(ASIDE) != eHtmlTag) + // { + // if (bResult) + // m_oState.m_eLastElement = eHtmlTag; + + // m_oState.m_bBanUpdatePageData = true; + // } + + // readNote(oXml, sSelectors, sNote); + arSelectors.pop_back(); + return bResult; +} + +bool CHTMLReader::ReadA(std::vector& arSelectors, CTextSettings& oTS) +{ + if (!m_mTags[HTML_TAG(A)]->Open(arSelectors, oTS)) + return false; + + if(!ReadStream(arSelectors, oTS)) + m_pInterpretator->WriteEmptyParagraph(true); + + m_mTags[HTML_TAG(A)]->Close(arSelectors); + + #ifdef _DEBUG + m_pInterpretator->PrintData(); + #endif + + return true; +} + +void CHTMLReader::GetSubClass(std::vector& sSelectors) +{ + NSCSS::CNode oNode; + + oNode.m_wsName = m_oLightReader.GetName(); + // Стиль по атрибуту + while(m_oLightReader.MoveToNextAttribute()) + { + std::wstring sName = m_oLightReader.GetName(); + if(sName == L"class") + oNode.m_wsClass = EncodeXmlString(m_oLightReader.GetText()); + else if(sName == L"id") + { + oNode.m_wsId = EncodeXmlString(m_oLightReader.GetText()); + // WriteEmptyBookmark(oXml, oNode.m_wsId); + + if (!m_oStylesCalculator.HaveStylesById(oNode.m_wsId)) + oNode.m_wsId.clear(); + } + else if(sName == L"style") + oNode.m_wsStyle += m_oLightReader.GetText(); + else + { + if (CheckArgumentMath(oNode.m_wsName, sName)) + oNode.m_mAttributes[sName] = m_oLightReader.GetText(); + } + } + m_oLightReader.MoveToElement(); + sSelectors.push_back(oNode); + + m_oStylesCalculator.CalculateCompiledStyle(sSelectors); +} + +inline std::wstring GetArgumentValue(XmlUtils::CXmlLiteReader& oLiteReader, const std::wstring& wsArgumentName, const std::wstring& wsDefaultValue) +{ + if (!oLiteReader.MoveToFirstAttribute()) + return wsDefaultValue; + + std::wstring wsValue{wsDefaultValue}; + + do + { + if (wsArgumentName == oLiteReader.GetName()) + { + wsValue = oLiteReader.GetText(); + break; + } + } while (oLiteReader.MoveToNextAttribute()); + + oLiteReader.MoveToElement(); + return wsValue; +} + +// Так как CSS калькулятор не знает для какой ноды производится расчет стиля +// и не знает, что некоторые стили предназначены только определенной ноде, +// то проще пока обрабатывать это заранее +// ! Используется для стилей, заданных через аргументы ! +inline bool CheckArgumentMath(const std::wstring& wsNodeName, const std::wstring& wsStyleName) +{ + if (L"border" == wsStyleName && L"table" != wsNodeName) + return false; + + return true; +} + +inline HtmlTag GetHtmlTag(const std::wstring& wsStrTag) +{ + std::map::const_iterator oFound = m_HTML_TAGS.find(wsStrTag); + + if (oFound == m_HTML_TAGS.cend()) + { + if (wsStrTag.length() > 3 && wsStrTag.compare(wsStrTag.length() - 3, 3, L"svg") == 0) + return HTML_TAG(SVG); + return UNKNOWN_TAG; + } + + return oFound->second; +} + +inline bool UnreadableNode(const std::wstring& wsNodeName) +{ + return L"head" == wsNodeName || L"meta" == wsNodeName || L"style" == wsNodeName; +} + +inline bool TagIsUnprocessed(const std::wstring& wsTagName) +{ + return L"xml" == wsTagName; +} +} diff --git a/HtmlFile2/HTMLReader.h b/HtmlFile2/HTMLReader.h new file mode 100644 index 0000000000..560b46fba0 --- /dev/null +++ b/HtmlFile2/HTMLReader.h @@ -0,0 +1,55 @@ +#ifndef HTMLREADER_H +#define HTMLREADER_H + +#include "../Common/3dParty/html/css/src/CCssCalculator.h" +#include "../DesktopEditor/xml/include/xmlutils.h" + +#include "HTMLInterpretator.h" +#include "Tags/HTMLTags.h" + +namespace HTML +{ +class CHTMLReader +{ + XmlUtils::CXmlLiteReader m_oLightReader; // SAX Reader + NSCSS::CCssCalculator m_oStylesCalculator; // Css калькулятор + + NSCSS::NSProperties::CPage m_oPageData; // Стили страницы + + std::wstring m_sTmp; // Temp папка + std::wstring m_sSrc; // Директория источника + std::wstring m_sDst; // Директория назначения + std::wstring m_sBase; // Полный базовый адрес + std::wstring m_sCore; // Путь до корневого файла (используется для работы с Epub) + + IHTMLInterpretator *m_pInterpretator; + + std::map m_mTags; +public: + CHTMLReader(); + ~CHTMLReader(); + + HRESULT ReadFromFile(const std::wstring& wsFileName); +private: + bool IsHTML(); + + bool HTML2XHTML(const std::wstring& wsFileName); + + void ReadStyle(); + void ReadStyle2(); + void ReadStyleFromNetwork(); + + void ReadDocument(); + void ReadHead(); + void ReadBody(); + + bool ReadStream(std::vector& arSelectors, CTextSettings& oTS, bool bInsertEmptyP = false); + bool ReadInside(std::vector& arSelectors, CTextSettings& oTS); + + bool ReadA(std::vector& arSelectors, CTextSettings& oTS); + + void GetSubClass(std::vector& sSelectors); +}; +} + +#endif // HTMLREADER_H diff --git a/HtmlFile2/HtmlFile2.pro b/HtmlFile2/HtmlFile2.pro index 780ed03313..59ba70256f 100644 --- a/HtmlFile2/HtmlFile2.pro +++ b/HtmlFile2/HtmlFile2.pro @@ -31,8 +31,17 @@ include($$CORE_ROOT_DIR/Common/3dParty/boost/boost.pri) ADD_DEPENDENCY(kernel, UnicodeConverter, graphics, kernel_network) -SOURCES += htmlfile2.cpp +SOURCES += htmlfile2.cpp \ + HTML2OOXMLInterpretator.cpp \ + HTMLReader.cpp HEADERS += htmlfile2.h \ ./src/StringFinder.h \ - ./src/Languages.h + ./src/Languages.h \ + Common.h \ + HTML2OOXMLInterpretator.h \ + HTMLInterpretator.h \ + HTMLReader.h \ + Tags/HTMLTags.h \ + Tags/HTMLTags2OOXML.h \ + TextSettings.h diff --git a/HtmlFile2/Tags/HTMLTags.h b/HtmlFile2/Tags/HTMLTags.h new file mode 100644 index 0000000000..c545b0fd26 --- /dev/null +++ b/HtmlFile2/Tags/HTMLTags.h @@ -0,0 +1,43 @@ +#ifndef HTMLTAGS_H +#define HTMLTAGS_H + +#include "../Common/3dParty/html/css/src/CNode.h" +#include "../TextSettings.h" + +namespace HTML +{ +struct ITag +{ + virtual ~ITag() = default; + virtual bool Open(std::vector& sSelectors, CTextSettings& oTS) = 0; + virtual void Close(std::vector& sSelectors) = 0; +}; + +template +struct TTag : public ITag +{ + T* m_pInterpretator; + + TTag(T* pInterpretator) + : m_pInterpretator(pInterpretator) + {} + virtual ~TTag() = default; + virtual bool Open(std::vector& sSelectors, CTextSettings& oTS) = 0; + virtual void Close(std::vector& sSelectors) = 0; + + bool ValidInterpretator() const + { + return nullptr != m_pInterpretator; + } +}; + +template +struct TAnchor : public TTag +{ + virtual bool Open(std::vector& sSelectors, CTextSettings& oTS) = 0; + virtual void Close(std::vector& sSelectors) = 0; +}; + +} + +#endif // HTMLTAGS_H diff --git a/HtmlFile2/Tags/HTMLTags2OOXML.h b/HtmlFile2/Tags/HTMLTags2OOXML.h new file mode 100644 index 0000000000..3a39786426 --- /dev/null +++ b/HtmlFile2/Tags/HTMLTags2OOXML.h @@ -0,0 +1,123 @@ +#ifndef HTMLTAGS2OOXML_H +#define HTMLTAGS2OOXML_H + +#include "HTMLTags.h" +#include "HTML2OOXMLInterpretator.h" + +namespace HTML +{ +template<> +struct TAnchor : public TTag +{ + TAnchor(CHTML2OOXMLInterpretator* pInterpretator) + : TTag(pInterpretator) + {} + + virtual bool Open(std::vector& arSelectors, CTextSettings& oTS) + { + if (!ValidInterpretator()) + return false; + + std::wstring wsRef; + std::wstring wsAlt; + bool bCross = false; + + std::map& mAttributes(arSelectors.back().m_mAttributes); + + std::map::const_iterator itFound = mAttributes.find(L"href"); + + bool bFounded = false; + + if (mAttributes.cend() != itFound) + { + wsRef = itFound->second; + if(wsRef.find('#') != std::wstring::npos) + bCross = true; + + bFounded = true; + } + else + itFound = mAttributes.find(L"name"); + + if (!bFounded) + { + if (mAttributes.cend() != itFound) + { + m_pInterpretator->WriteBookmark(itFound->second); + bFounded = true; + } + else + itFound = mAttributes.find(L"alt"); + } + + if (!bFounded) + { + if (mAttributes.cend() != itFound) + { + wsAlt = itFound->second; + bFounded = true; + } + } + + if (!bFounded) + return false; + + std::wstring wsTooltip(wsRef); + + itFound = mAttributes.find(L"title"); + + if (mAttributes.cend() != itFound) + wsTooltip = itFound->second; + + if (bCross) + m_pInterpretator->OpenCrossHyperlink(wsRef, arSelectors, oTS); + else + m_pInterpretator->OpenExternalHyperlink(wsRef, wsTooltip, arSelectors, oTS); + + return true; + } + virtual void Close(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return; + + bool bCross = false; + std::wstring wsFootnote; + + std::map& mAttributes(arSelectors.back().m_mAttributes); + std::map::const_iterator itFound; + + if (arSelectors.back().m_wsStyle.find(L"mso-footnote-id") != std::wstring::npos) + wsFootnote = arSelectors.back().m_wsStyle.substr(arSelectors.back().m_wsStyle.rfind(L':') + 1); + else + { + itFound = mAttributes.find(L"epub:type"); + + if (mAttributes.cend() != itFound && itFound->second.find(L"noteref")) + wsFootnote = L"href"; + } + + std::wstring wsRef; + itFound = mAttributes.find(L"href"); + + if (mAttributes.cend() != itFound) + { + wsRef = itFound->second; + if(itFound->second.find('#') != std::wstring::npos) + bCross = true; + } + + if (bCross) + { + if (wsFootnote == L"href") + wsFootnote = wsRef.substr(wsRef.find('#') + 1); + + m_pInterpretator->CloseCrossHyperlink(arSelectors, wsFootnote, wsRef); + } + else + m_pInterpretator->CloseExternalHyperlink(); + } +}; +} + +#endif // HTMLTAGS2OOXML_H diff --git a/HtmlFile2/TextSettings.h b/HtmlFile2/TextSettings.h new file mode 100644 index 0000000000..7e71d9c90f --- /dev/null +++ b/HtmlFile2/TextSettings.h @@ -0,0 +1,48 @@ +#ifndef TEXTSETTINGS_H +#define TEXTSETTINGS_H + +#include "../Common/3dParty/html/css/src/CCompiledStyle.h" + +namespace HTML +{ +// Настройки текста +struct CTextSettings +{ + bool bBdo; // Реверс текста + bool bPre; // Сохранение форматирования (Сохранение пробелов, табуляций, переносов строк) + bool bQ; // Цитата + bool bAddSpaces; // Добавлять пробелы перед текстом? + bool bMergeText; // Объединять подряд идущий текст в 1? + int nLi; // Уровень списка + bool bNumberingLi; // Является ли список нумерованным + + std::wstring sPStyle; + + enum ETextMode + { + Normal, + Superscript, + Subscript + } eTextMode; + + NSCSS::CCompiledStyle oAdditionalStyle; + + CTextSettings() + : bBdo(false), bPre(false), bQ(false), bAddSpaces(true), bMergeText(false), nLi(-1), bNumberingLi(false), eTextMode(Normal) + {} + + CTextSettings(const CTextSettings& oTS) : + bBdo(oTS.bBdo), bPre(oTS.bPre), bQ(oTS.bQ), bAddSpaces(oTS.bAddSpaces), bMergeText(oTS.bMergeText), + nLi(oTS.nLi), bNumberingLi(oTS.bNumberingLi), sPStyle(oTS.sPStyle), eTextMode(oTS.eTextMode), + oAdditionalStyle(oTS.oAdditionalStyle) + {} + + void AddPStyle(const std::wstring& wsStyle) + { + if (std::wstring::npos == sPStyle.find(wsStyle)) + sPStyle += wsStyle; + } +}; +} + +#endif // TEXTSETTINGS_H diff --git a/HtmlFile2/htmlfile2.cpp b/HtmlFile2/htmlfile2.cpp index 25f752ec87..dff9f0253e 100644 --- a/HtmlFile2/htmlfile2.cpp +++ b/HtmlFile2/htmlfile2.cpp @@ -28,6 +28,8 @@ #include +#include "HTMLReader.h" + #ifndef VALUE2STR #define VALUE_TO_STRING(x) #x #define VALUE2STR(x) VALUE_TO_STRING(x) @@ -267,7 +269,7 @@ struct CTextSettings bool bPre; // Сохранение форматирования (Сохранение пробелов, табуляций, переносов строк) bool bQ; // Цитата bool bAddSpaces; // Добавлять пробелы перед текстом? - bool bMergeText; // Объединять подяр идущий текст в 1? + bool bMergeText; // Объединять подряд идущий текст в 1? int nLi; // Уровень списка bool bNumberingLi; // Является ли список нумерованным @@ -2488,16 +2490,6 @@ private: sSelectors.push_back(NSCSS::CNode(L"html", L"", L"")); GetSubClass(&m_oDocXml, sSelectors); - /* - std::wstring sCrossId = std::to_wstring(m_nCrossId++); - m_oDocXml.WriteString(L""); - */ if (!sSelectors.back().m_mAttributes.empty()) { @@ -2688,7 +2680,9 @@ private: pXml->WriteEncodeXmlString(wsNote); pXml->WriteString(L"\""); pXml->WriteString(L""); + const bool bResult = readStream(pXml, arSelectors, oTS); + pXml->WriteString(L""); wsNote.clear(); @@ -5122,6 +5116,10 @@ void CHtmlFile2::SetCoreDirectory(const std::wstring& wsFolder) HRESULT CHtmlFile2::OpenHtml(const std::wstring& sSrc, const std::wstring& sDst, CHtmlParams* oParams) { + HTML::CHTMLReader oHTMLReader; + + oHTMLReader.ReadFromFile(sSrc); + if(!m_internal->m_oLightReader.IsValid()) if(!IsHtmlFile(sSrc)) return S_FALSE; diff --git a/HtmlFile2/test/main.cpp b/HtmlFile2/test/main.cpp index eb2fb2553c..ea6d1abe70 100644 --- a/HtmlFile2/test/main.cpp +++ b/HtmlFile2/test/main.cpp @@ -6,6 +6,13 @@ #include "../../DesktopEditor/common/Directory.h" #include "../../OfficeUtils/src/OfficeUtils.h" +#include "../../Common/3dParty/md/md2html.h" + +#include +#include +#include +#include + void getDirectories(const std::wstring& sDirectory, std::vector& arrDirectory) { arrDirectory.push_back(sDirectory); @@ -15,6 +22,15 @@ void getDirectories(const std::wstring& sDirectory, std::vector& a int main() { + // if (Md::ConvertMdFileToHtml(L"C:\\ONLYOFFICE\\Files\\md\\Bugs\\74626\\file-1.md", + // L"C:\\ONLYOFFICE\\Files\\md\\Bugs\\74626\\file-1.html")) + // std::wcout << L"Good" << std::endl; + // else + // std::wcout << L"Bad" << std::endl; + + // return 0; + + bool bBatchMode = false; bool bMhtMode = false; if(bBatchMode) @@ -97,7 +113,7 @@ int main() oParams.SetDescription(L"Description"); // Файл, который открываем - std::wstring sFile = NSFile::GetProcessDirectory() + L"/test.html"; + std::wstring sFile = L"C:\\ONLYOFFICE\\Files\\html\\test_tag_a_1.html"; CHtmlFile2 oFile; oFile.SetTmpDirectory(sOutputDirectory); nResConvert = (bMhtMode ? oFile.OpenMht(sFile, sOutputDirectory, &oParams) : oFile.OpenHtml(sFile, sOutputDirectory, &oParams));