From e32b48524e7a7508775e1e46a4f5fcb38474e7d7 Mon Sep 17 00:00:00 2001 From: Kirill Polyakov Date: Thu, 22 Jan 2026 20:16:47 +0300 Subject: [PATCH] Migrated most of the html conversion to the new architecture --- .../html/css/src/CCssCalculator_Private.cpp | 117 ++- .../html/css/src/CCssCalculator_Private.h | 5 + Common/3dParty/html/css/src/CElement.cpp | 8 +- Common/3dParty/html/css/src/CElement.h | 1 + Common/3dParty/html/css/src/CNode.cpp | 17 + Common/3dParty/html/css/src/CNode.h | 3 + HtmlFile2/HTML2OOXMLInterpretator.cpp | 893 +++++++++++++++++- HtmlFile2/HTML2OOXMLInterpretator.h | 31 +- HtmlFile2/HTMLInterpretator.h | 49 +- HtmlFile2/HTMLParams.h | 69 ++ HtmlFile2/HTMLReader.cpp | 466 ++++----- HtmlFile2/HTMLReader.h | 20 +- HtmlFile2/HtmlFile2.pro | 1 + HtmlFile2/Tags/HTMLTags.h | 48 +- HtmlFile2/Tags/HTMLTags2OOXML.h | 278 ++++-- HtmlFile2/TextSettings.h | 65 +- HtmlFile2/htmlfile2.cpp | 16 +- 17 files changed, 1682 insertions(+), 405 deletions(-) create mode 100644 HtmlFile2/HTMLParams.h diff --git a/Common/3dParty/html/css/src/CCssCalculator_Private.cpp b/Common/3dParty/html/css/src/CCssCalculator_Private.cpp index 1deffe5bfb..ed082aba8b 100644 --- a/Common/3dParty/html/css/src/CCssCalculator_Private.cpp +++ b/Common/3dParty/html/css/src/CCssCalculator_Private.cpp @@ -15,29 +15,31 @@ inline static std::wstring StringifyValueList(const KatanaArray* oValues); inline static std::wstring StringifyValue(const KatanaValue* oValue); inline static bool IsTableElement(const std::wstring& wsNameTag); -bool operator<(const std::vector &arLeftSelectors, const std::vector &arRightSelectors) -{ - const size_t& sizeLeftSelectors = arLeftSelectors.size(); - const size_t& sizeRightSelectors = arRightSelectors.size(); - - if (sizeLeftSelectors < sizeRightSelectors) - return true; - else if (sizeLeftSelectors > sizeRightSelectors) - return false; - - for (size_t i = 0; i < arLeftSelectors.size(); ++i) - { - if (arLeftSelectors[i] < arRightSelectors[i]) - return true; - } - - return false; -} - namespace NSCSS { + bool operator<(const std::vector &arLeftSelectors, const std::vector &arRightSelectors) + { + const size_t& sizeLeftSelectors = arLeftSelectors.size(); + const size_t& sizeRightSelectors = arRightSelectors.size(); + + if (sizeLeftSelectors < sizeRightSelectors) + return true; + else if (sizeLeftSelectors > sizeRightSelectors) + return false; + + for (size_t i = 0; i < arLeftSelectors.size(); ++i) + { + if (arLeftSelectors[i] < arRightSelectors[i]) + return true; + } + + return false; + } + CStyleStorage::CStyleStorage() - {} + { + InitDefaultStyles(); + } CStyleStorage::~CStyleStorage() { @@ -62,6 +64,7 @@ namespace NSCSS m_arEmptyStyleFiles.clear(); ClearEmbeddedStyles(); + ClearDefaultStyles(); ClearAllowedStyleFiles(); #ifdef CSS_CALCULATOR_WITH_XHTML @@ -208,6 +211,16 @@ namespace NSCSS return nullptr; } + const CElement* CStyleStorage::FindDefaultElement(const std::wstring& wsSelector) const + { + if (wsSelector.empty()) + return nullptr; + + const CElement* pFoundElement = FindSelectorFromStyleData(wsSelector, m_mDefaultStyleData); + + return (nullptr != pFoundElement) ? pFoundElement : nullptr; + } + void CStyleStorage::AddStyles(const std::string& sStyle, std::map& mStyleData) { if (sStyle.empty()) @@ -227,6 +240,15 @@ namespace NSCSS m_mEmbeddedStyleData.clear(); } + void CStyleStorage::ClearDefaultStyles() + { + for (std::map::iterator oIter = m_mDefaultStyleData.begin(); oIter != m_mDefaultStyleData.end(); ++oIter) + if (oIter->second != nullptr) + delete oIter->second; + + m_mDefaultStyleData.clear(); + } + void CStyleStorage::ClearAllowedStyleFiles() { m_arAllowedStyleFiles.clear(); @@ -480,7 +502,31 @@ namespace NSCSS return nullptr; } - CCssCalculator_Private::CCssCalculator_Private() : m_nDpi(96), m_nCountNodes(0), m_sEncoding(L"UTF-8"){} + void CStyleStorage::InitDefaultStyles() + { + m_mDefaultStyleData[L"b"] = new CElement(L"b", {{L"font-weight", L"bold"}}); + m_mDefaultStyleData[L"center"] = new CElement(L"center", {{L"text-align", L"center"}}); + m_mDefaultStyleData[L"i"] = new CElement(L"i", {{L"font-style", L"italic"}}); + m_mDefaultStyleData[L"code"] = new CElement(L"code", {{L"font-family", L"Courier New"}}); + m_mDefaultStyleData[L"kbd"] = new CElement(L"kbd", {{L"font-family", L"Courier New"}, + {L"font-size", L"20pt"}, + {L"font_weight", L"bold"}}); + m_mDefaultStyleData[L"s"] = new CElement(L"s", {{L"text-decoration", L"line-through"}}); + m_mDefaultStyleData[L"u"] = new CElement(L"u", {{L"text-decoration", L"underline"}}); + m_mDefaultStyleData[L"mark"] = new CElement(L"mark", {{L"background-color", L"yellow"}}); + m_mDefaultStyleData[L"sup"] = new CElement(L"sup", {{L"vertical-align", L"super"}}); + m_mDefaultStyleData[L"sub"] = new CElement(L"sub", {{L"vertical-align", L"sub"}}); + m_mDefaultStyleData[L"dd"] = new CElement(L"dd", {{L"margin-left", L"720tw"}}); + m_mDefaultStyleData[L"pre"] = new CElement(L"pre", {{L"font-family", L"Courier New"}, + {L"font-size", L"20pt"}, + {L"margin-top", L"0"}, + {L"margin-bottom", L"0"}}); + } + + CCssCalculator_Private::CCssCalculator_Private() + : m_nDpi(96), m_nCountNodes(0), m_sEncoding(L"UTF-8") + { + } CCssCalculator_Private::~CCssCalculator_Private() {} @@ -644,6 +690,30 @@ namespace NSCSS arFindedElements.insert(arFindedElements.end(), arTempKins.begin(), arTempKins.end()); } + inline std::wstring GetAlternativeDefaultNodeName(const std::wstring& wsNodeName) + { + if (L"strong" == wsNodeName) + return L"b"; + + if (L"cite" == wsNodeName || L"dfn" == wsNodeName || L"em" == wsNodeName || + L"var" == wsNodeName || L"adress" == wsNodeName) + return L"i"; + + if (L"tt" == wsNodeName || L"samp" == wsNodeName) + return L"code"; + + if (L"strike" == wsNodeName || L"del" == wsNodeName) + return L"s"; + + if (L"ins" == wsNodeName) + return L"u"; + + if (L"xmp" == wsNodeName || L"nobr" == wsNodeName) + return L"pre"; + + return wsNodeName; + } + std::vector CCssCalculator_Private::FindElements(std::vector &arNodes, std::vector &arNextNodes) { if (arNodes.empty()) @@ -702,6 +772,11 @@ namespace NSCSS } } + const CElement* pFoundDefault = m_oStyleStorage.FindDefaultElement(GetAlternativeDefaultNodeName(wsName)); + + if (nullptr != pFoundDefault) + arFindedElements.push_back(pFoundDefault); + const CElement* pFoundName = m_oStyleStorage.FindElement(wsName); if (nullptr != pFoundName) diff --git a/Common/3dParty/html/css/src/CCssCalculator_Private.h b/Common/3dParty/html/css/src/CCssCalculator_Private.h index 2f6543a4a4..21bb227781 100644 --- a/Common/3dParty/html/css/src/CCssCalculator_Private.h +++ b/Common/3dParty/html/css/src/CCssCalculator_Private.h @@ -27,6 +27,7 @@ namespace NSCSS void AddStylesFromFile(const std::wstring& wsFileName); void ClearEmbeddedStyles(); + void ClearDefaultStyles(); void ClearAllowedStyleFiles(); void ClearStylesFromFile(const std::wstring& wsFileName); @@ -38,6 +39,7 @@ namespace NSCSS #endif const CElement* FindElement(const std::wstring& wsSelector) const; + const CElement* FindDefaultElement(const std::wstring& wsSelector) const; private: typedef struct { @@ -49,6 +51,7 @@ namespace NSCSS std::set m_arAllowedStyleFiles; std::vector m_arStyleFiles; std::map m_mEmbeddedStyleData; + std::map m_mDefaultStyleData; #ifdef CSS_CALCULATOR_WITH_XHTML typedef struct @@ -78,6 +81,8 @@ namespace NSCSS void GetOutputData(KatanaOutput* oOutput, std::map& mStyleData); const CElement* FindSelectorFromStyleData(const std::wstring& wsSelector, const std::map& mStyleData) const; + + void InitDefaultStyles(); }; class CCssCalculator_Private diff --git a/Common/3dParty/html/css/src/CElement.cpp b/Common/3dParty/html/css/src/CElement.cpp index 22a06291f5..d1d29a5f1e 100644 --- a/Common/3dParty/html/css/src/CElement.cpp +++ b/Common/3dParty/html/css/src/CElement.cpp @@ -9,6 +9,13 @@ namespace NSCSS CElement::CElement() { } + + CElement::CElement(const std::wstring& wsSelector, std::map mStyle) + : m_mStyle(mStyle), m_sSelector(wsSelector), m_sFullSelector(wsSelector) + { + UpdateWeight(); + } + CElement::~CElement() { for (CElement* oElement : m_arPrevElements) @@ -18,7 +25,6 @@ namespace NSCSS continue; m_mStyle.clear(); - } std::wstring CElement::GetSelector() const diff --git a/Common/3dParty/html/css/src/CElement.h b/Common/3dParty/html/css/src/CElement.h index c606ac1983..9bc739a980 100644 --- a/Common/3dParty/html/css/src/CElement.h +++ b/Common/3dParty/html/css/src/CElement.h @@ -22,6 +22,7 @@ namespace NSCSS public: CElement(); + CElement(const std::wstring& wsSelector, std::map mStyle); ~CElement(); std::wstring GetSelector() const; diff --git a/Common/3dParty/html/css/src/CNode.cpp b/Common/3dParty/html/css/src/CNode.cpp index 53693e0f34..28a14f5b2f 100644 --- a/Common/3dParty/html/css/src/CNode.cpp +++ b/Common/3dParty/html/css/src/CNode.cpp @@ -42,6 +42,23 @@ namespace NSCSS return m_wsName.empty() && m_wsClass.empty() && m_wsId.empty() && m_wsStyle.empty(); } + bool CNode::GetAttributeValue(const std::wstring& wsAttributeName, std::wstring& wsAttributeValue) const + { + const std::map::const_iterator itFound{m_mAttributes.find(wsAttributeName)}; + + if (m_mAttributes.cend() == itFound) + return false; + + wsAttributeValue = itFound->second; + return true; + } + + std::wstring CNode::GetAttributeValue(const std::wstring& wsAttributeName) const + { + const std::map::const_iterator itFound{m_mAttributes.find(wsAttributeName)}; + return (m_mAttributes.cend() != itFound) ? itFound->second : std::wstring(); + } + #ifdef CSS_CALCULATOR_WITH_XHTML void CNode::SetCompiledStyle(CCompiledStyle* pCompiledStyle) { diff --git a/Common/3dParty/html/css/src/CNode.h b/Common/3dParty/html/css/src/CNode.h index 9e039e7958..ed939c2cbe 100644 --- a/Common/3dParty/html/css/src/CNode.h +++ b/Common/3dParty/html/css/src/CNode.h @@ -31,6 +31,9 @@ namespace NSCSS bool Empty() const; + bool GetAttributeValue(const std::wstring& wsAttributeName, std::wstring& wsAttributeValue) const; + std::wstring GetAttributeValue(const std::wstring& wsAttributeName) const; + #ifdef CSS_CALCULATOR_WITH_XHTML void SetCompiledStyle(CCompiledStyle* pCompiledStyle); #endif diff --git a/HtmlFile2/HTML2OOXMLInterpretator.cpp b/HtmlFile2/HTML2OOXMLInterpretator.cpp index 4b4d3b9c92..5205aef544 100644 --- a/HtmlFile2/HTML2OOXMLInterpretator.cpp +++ b/HtmlFile2/HTML2OOXMLInterpretator.cpp @@ -1,16 +1,352 @@ #include "HTML2OOXMLInterpretator.h" +#include + #include "../DesktopEditor/common/File.h" +#include "../DesktopEditor/common/Directory.h" +#include "../DesktopEditor/common/SystemUtils.h" + +#include "src/Languages.h" + #include #include namespace HTML { +#ifndef VALUE2STR +#define VALUE_TO_STRING(x) #x +#define VALUE2STR(x) VALUE_TO_STRING(x) +#endif + +#define MAX_STRING_BLOCK_SIZE (size_t)10485760 + +#define MAXCOLUMNSINTABLE 63 +#define MAXROWSINTABLE 32767 + +#define DEFAULT_PAGE_WIDTH 12240 // Значение в Twips +#define DEFAULT_PAGE_HEIGHT 15840 // Значение в Twips + +#define DEFAULT_LANGUAGE std::wstring(L"en-US") +#define DEFAULT_FONT_FAMILY std::wstring(L"Times New Roman") +#define DEFAULT_FONT_SIZE 24 + +#define DEFAULT_IMAGE_WIDTH 304800 +#define DEFAULT_IMAGE_HEIGHT 304800 + inline bool ElementInTable(const std::vector& arSelectors); +inline void WriteToStringBuilder(NSStringUtils::CStringBuilder& oSrcStringBuilder, NSStringUtils::CStringBuilder& oDstStringBuilder); +inline bool ElementInHeader(const std::vector arSelsectors); +inline std::wstring StandardizeHeaderId(const std::wstring& wsHeader); +inline int CalculateFontChange(const std::vector& arSelectors); +inline UINT GetFontSizeLevel(UINT unFontSize); +inline UINT GetFontSizeByLevel(UINT unLevel); +inline void ReplaceSpaces(std::wstring& wsValue); +inline void replace_all(std::wstring& s, const std::wstring& s1, const std::wstring& s2); +inline std::wstring EncodeXmlString(std::wstring wsString); CHTML2OOXMLInterpretator::CHTML2OOXMLInterpretator() : m_pCurrentDocument(&m_oDocXml), m_nFootnoteId(1), m_nHyperlinkId(1), m_nNumberingId(1), m_nId(1), m_nShapeId(1) -{} +{ + m_oPageData.SetWidth (DEFAULT_PAGE_WIDTH, NSCSS::UnitMeasure::Twips, 0, true); + m_oPageData.SetHeight(DEFAULT_PAGE_HEIGHT, NSCSS::UnitMeasure::Twips, 0, true); + m_oPageData.SetMargin(1440, NSCSS::UnitMeasure::Twips, 0, true); + m_oPageData.SetFooter(720, NSCSS::UnitMeasure::Twips, 0, true); + m_oPageData.SetHeader(720, NSCSS::UnitMeasure::Twips, 0, true); +} + +void CHTML2OOXMLInterpretator::Begin(const std::wstring& wsDst, const THtmlParams* pParams) +{ + // Создаем пустые папки + NSDirectory::CreateDirectory(wsDst + L"/_rels"); + NSDirectory::CreateDirectory(wsDst + L"/docProps"); + NSDirectory::CreateDirectory(wsDst + L"/word"); + NSDirectory::CreateDirectory(wsDst + L"/word/_rels"); + NSDirectory::CreateDirectory(wsDst + L"/word/media"); + NSDirectory::CreateDirectory(wsDst + L"/word/theme"); + + // theme1.xml + std::wstring sTheme = L""; + NSFile::CFileBinary oThemeWriter; + if (oThemeWriter.CreateFileW(wsDst + L"/word/theme/theme1.xml")) + { + oThemeWriter.WriteStringUTF8(sTheme); + oThemeWriter.CloseFile(); + } + + // app.xml + std::wstring sApplication = NSSystemUtils::GetEnvVariable(NSSystemUtils::gc_EnvApplicationName); + if (sApplication.empty()) + sApplication = NSSystemUtils::gc_EnvApplicationNameDefault; + #if defined(INTVER) + const std::string sVersion = VALUE2STR(INTVER); + #else + const std::string sVersion{L"1.0"}; + #endif + std::wstring sApp = L""; + sApp += sApplication + L"/" + UTF8_TO_U(sVersion); + sApp += L"0falsefalsefalsefalse"; + NSFile::CFileBinary oAppWriter; + if (oAppWriter.CreateFileW(wsDst + L"/docProps/app.xml")) + { + oAppWriter.WriteStringUTF8(sApp); + oAppWriter.CloseFile(); + } + + // .rels + std::wstring sRels = L""; + NSFile::CFileBinary oRelsWriter; + if (oRelsWriter.CreateFileW(wsDst + L"/_rels/.rels")) + { + oRelsWriter.WriteStringUTF8(sRels); + oRelsWriter.CloseFile(); + } + + // [Content_Types].xml + std::wstring sContent = L""; + NSFile::CFileBinary oContentWriter; + if (oContentWriter.CreateFileW(wsDst + L"/[Content_Types].xml")) + { + oContentWriter.WriteStringUTF8(sContent); + oContentWriter.CloseFile(); + } + + // fontTable.xml + std::wstring sFontTable = L""; + NSFile::CFileBinary oFontTableWriter; + if (oFontTableWriter.CreateFileW(wsDst + L"/word/fontTable.xml")) + { + oFontTableWriter.WriteStringUTF8(sFontTable); + oFontTableWriter.CloseFile(); + } + + // settings.xml + std::wstring sSettings = L""; + NSFile::CFileBinary oSettingsWriter; + if (oSettingsWriter.CreateFileW(wsDst + L"/word/settings.xml")) + { + oSettingsWriter.WriteStringUTF8(sSettings); + oSettingsWriter.CloseFile(); + } + + // numbering.xml + // Маркированный список + m_oNumberXml += L""; + + std::wstring wsCurrentLanguage; + + // core.xml + std::wstring sCore = L""; + if(pParams) + { + if(!pParams->m_sBookTitle.empty()) + { + sCore += L""; + sCore += EncodeXmlString(pParams->m_sBookTitle); + sCore += L""; + } + if(!pParams->m_sAuthors.empty()) + { + sCore += L""; + sCore += EncodeXmlString(pParams->m_sAuthors); + sCore += L""; + } + if(!pParams->m_sGenres.empty()) + { + sCore += L""; + sCore += EncodeXmlString(pParams->m_sGenres); + sCore += L""; + } + if(!pParams->m_sDate.empty()) + { + sCore += L""; + sCore += EncodeXmlString(pParams->m_sDate); + sCore += L""; + } + if(!pParams->m_sDescription.empty()) + { + sCore += L""; + sCore += EncodeXmlString(pParams->m_sDescription); + sCore += L""; + } + if (!pParams->m_sLanguage.empty()) + { + wsCurrentLanguage = IndentifyLanguage(pParams->m_sLanguage); + + sCore += L""; + sCore += wsCurrentLanguage; + sCore += L""; + } + } + sCore += L""; + NSFile::CFileBinary oCoreWriter; + if (oCoreWriter.CreateFileW(wsDst + L"/docProps/core.xml")) + { + oCoreWriter.WriteStringUTF8(sCore); + oCoreWriter.CloseFile(); + } + + // Начала файлов + m_oDocXmlRels += L""; + m_oDocXmlRels += L""; + m_oDocXmlRels += L""; + m_oDocXmlRels += L""; + m_oDocXmlRels += L""; + m_oDocXmlRels += L""; + m_oDocXmlRels += L""; + m_oDocXmlRels += L""; + m_oNoteXmlRels += L""; + m_oDocXml += L""; + m_oNoteXml += L""; + m_oNoteXml += L""; + m_oStylesXml += L""; + m_oWebSettings += L""; + + m_nId += 7; + + // docDefaults по умолчанию + if(pParams && !pParams->m_sdocDefaults.empty()) + m_oStylesXml += pParams->m_sdocDefaults; + else + { + m_oStylesXml += L""; + m_oStylesXml += L""; + m_oStylesXml += L""; + m_oStylesXml += L""; + m_oStylesXml += L""; + +// m_oStylesXml += L""; + } + + // normal по умолчанию + if(pParams && !pParams->m_sNormal.empty()) + m_oStylesXml += pParams->m_sNormal; + else + { + m_oStylesXml += L""; + m_oStylesXml += L""; + m_oStylesXml += L""; + } + + // Маркированный список + m_oStylesXml += L""; + // Ссылки + m_oStylesXml += L""; + // Таблицы +// m_oStylesXml += L""; + // Сноски + m_oStylesXml += L""; + // Web стиль по-умолчанию + m_oStylesXml += L""; +} + +void CHTML2OOXMLInterpretator::End(const std::wstring& wsDst) +{ + m_oDocXmlRels.WriteString(L""); + NSFile::CFileBinary oRelsWriter; + if (oRelsWriter.CreateFileW(wsDst + L"/word/_rels/document.xml.rels")) + { + oRelsWriter.WriteStringUTF8(m_oDocXmlRels.GetData()); + oRelsWriter.CloseFile(); + } + + for (const std::pair& oFootnote : m_mFootnotes) + { + m_oNoteXml.WriteString(L""); + m_oNoteXml.WriteEncodeXmlString(oFootnote.first); + m_oNoteXml.WriteString(L""); + } + + m_oNoteXmlRels.WriteString(L""); + if (oRelsWriter.CreateFileW(wsDst + L"/word/_rels/footnotes.xml.rels")) + { + oRelsWriter.WriteStringUTF8(m_oNoteXmlRels.GetData()); + oRelsWriter.CloseFile(); + } + + if (m_oState.m_bInP) + m_oDocXml.WriteString(L""); + + m_oDocXml.WriteString(L""); + m_oDocXml.WriteString(L""); + m_oDocXml.WriteString(L""); + + NSFile::CFileBinary oDocumentWriter; + if (oDocumentWriter.CreateFileW(wsDst + L"/word/document.xml")) + { + oDocumentWriter.WriteStringUTF8(m_oDocXml.GetData()); + oDocumentWriter.CloseFile(); + } + + m_oNoteXml.WriteString(L""); + NSFile::CFileBinary oFootnotesWriter; + if (oFootnotesWriter.CreateFileW(wsDst + L"/word/footnotes.xml")) + { + oFootnotesWriter.WriteStringUTF8(m_oNoteXml.GetData()); + oFootnotesWriter.CloseFile(); + } + + // styles.xml + m_oStylesXml.WriteString(L""); + NSFile::CFileBinary oStylesWriter; + if (oStylesWriter.CreateFileW(wsDst + L"/word/styles.xml")) + { + oStylesWriter.WriteStringUTF8(m_oStylesXml.GetData()); + oStylesWriter.CloseFile(); + } + + // numbering.xml + // Маркированный список + m_oNumberXml.WriteString(L""); + // Нумерованный список + for(int i = 1; i < m_nNumberingId; i++) + { + m_oNumberXml.WriteString(L""); + } + m_oNumberXml.WriteString(L""); + NSFile::CFileBinary oNumberingWriter; + if (oNumberingWriter.CreateFileW(wsDst + L"/word/numbering.xml")) + { + oNumberingWriter.WriteStringUTF8(m_oNumberXml.GetData()); + oNumberingWriter.CloseFile(); + } + + // webSettings.xml + if (!m_mDivs.empty()) + m_oWebSettings.WriteString(L""); + + m_oWebSettings.WriteString(L""); + NSFile::CFileBinary oWebSettingsWriter; + if (oWebSettingsWriter.CreateFileW(wsDst + L"/word/webSettings.xml")) + { + oWebSettingsWriter.WriteStringUTF8(m_oWebSettings.GetData()); + oWebSettingsWriter.CloseFile(); + } +} bool CHTML2OOXMLInterpretator::OpenP() { @@ -85,12 +421,38 @@ void CHTML2OOXMLInterpretator::CloseT() m_oState.m_bInT = false; } -void CHTML2OOXMLInterpretator::OpenCrossHyperlink(const std::wstring& wsRef, std::vector& arSelectors, CTextSettings& oTS) +void CHTML2OOXMLInterpretator::BeginBlock(std::vector& arSelectors) +{ + m_pCurrentDocument = new XmlString(); + //Сохранить состояние + + CloseP(arSelectors); +} + +void CHTML2OOXMLInterpretator::EndBlock(bool bAddBlock, std::vector& arSelectors) +{ + if (m_pCurrentDocument == &m_oDocXml) + return; + + // readNote(&oXmlData, sSelectors, sNote); + + CloseP(arSelectors); + + if (bAddBlock) + WriteToStringBuilder(*m_pCurrentDocument, m_oDocXml); + // else + // m_oState = oCurentState; + + delete m_pCurrentDocument; + m_pCurrentDocument = &m_oDocXml; +} + +void CHTML2OOXMLInterpretator::OpenCrossHyperlink(const std::wstring& wsRef, std::vector& arSelectors) { if (!OpenP()) CloseR(); else - WritePPr(arSelectors, oTS); + WritePPr(arSelectors); m_oState.m_bInHyperlink = true; @@ -110,12 +472,12 @@ void CHTML2OOXMLInterpretator::OpenCrossHyperlink(const std::wstring& wsRef, std m_pCurrentDocument->WriteString(L"\">"); } -void CHTML2OOXMLInterpretator::OpenExternalHyperlink(const std::wstring& wsRef, const std::wstring& wsTooltip, std::vector& arSelectors, CTextSettings& oTS) +void CHTML2OOXMLInterpretator::OpenExternalHyperlink(const std::wstring& wsRef, const std::wstring& wsTooltip, std::vector& arSelectors) { if (!OpenP()) CloseR(); else - WritePPr(arSelectors, oTS); + WritePPr(arSelectors); // Пишем рельсы XmlString& oRelationshipXml(m_oDocXmlRels); @@ -185,7 +547,23 @@ void CHTML2OOXMLInterpretator::CloseExternalHyperlink() m_oState.m_bInHyperlink = false; } -std::wstring CHTML2OOXMLInterpretator::WritePPr(std::vector& arSelectors, CTextSettings& oTS) +void CHTML2OOXMLInterpretator::OpenFldChar(const std::wstring& wsNote) +{ + const std::wstring wsName{L"Bookmark" + std::to_wstring(m_mBookmarks.size() + 1)}; + m_mBookmarks.insert(std::make_pair(wsName, m_mBookmarks.size() + 1)); + + m_pCurrentDocument->WriteString(L"HYPERLINK \\l \"" + wsName + L"\" \\o \""); + m_pCurrentDocument->WriteEncodeXmlString(wsNote); + m_pCurrentDocument->WriteString(L"\""); + m_pCurrentDocument->WriteString(L""); +} + +void CHTML2OOXMLInterpretator::CloseFldChar() +{ + m_pCurrentDocument->WriteString(L""); +} + +std::wstring CHTML2OOXMLInterpretator::WritePPr(const std::vector& arSelectors) { OpenP(); @@ -197,12 +575,12 @@ std::wstring CHTML2OOXMLInterpretator::WritePPr(std::vector& arSel if (sPStyle.empty() && !ElementInTable(arSelectors)) sPStyle = L"normal-web"; - if (sPStyle.empty() && oTS.sPStyle.empty() && 0 > oTS.nLi) + 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_oXmlStyle.WriteLitePStyle(oTS.oAdditionalStyle); + // const std::wstring sPSettings = m_oXmlStyle.GetStyle(); + // m_oXmlStyle.Clear(); m_pCurrentDocument->WriteNodeBegin(L"w:pPr"); @@ -213,17 +591,254 @@ std::wstring CHTML2OOXMLInterpretator::WritePPr(std::vector& arSel m_pCurrentDocument->WriteString(L"\"/>"); } - if (oTS.nLi >= 0) - m_pCurrentDocument->WriteString(L""); + int nLiLevel{-1}; + bool bNumberingLi{false}; - m_pCurrentDocument->WriteString(oTS.sPStyle + sPSettings); + for (const NSCSS::CNode& oNode : arSelectors) + { + if (L"ol" == oNode.m_wsName) + bNumberingLi = true; + else if (L"li" == oNode.m_wsName) + bNumberingLi = false; + else + continue; + + ++nLiLevel; + } + + if (nLiLevel >= 0) + m_pCurrentDocument->WriteString(L""); + + // m_pCurrentDocument->WriteString(oTS.sPStyle + sPSettings); m_pCurrentDocument->WriteNodeEnd(L"w:pPr"); m_oState.m_bWasPStyle = true; return sPStyle; } +std::wstring CHTML2OOXMLInterpretator::WriteRPr(XmlString& oXml, const std::vector& arSelectors) +{ + if (!m_oState.m_bInP) + return L""; + + NSCSS::CCompiledStyle *pMainStyle{arSelectors.back().m_pCompiledStyle}; + std::wstring sRSettings; + + std::wstring sRStyle = GetStyle(*pMainStyle, false); + + // if (!oTS.oAdditionalStyle.Empty()) + // { + // NSCSS::CCompiledStyle oSettingStyle{oTS.oAdditionalStyle}; + + // NSCSS::CCompiledStyle::StyleEquation(oMainStyle, oSettingStyle); + + // m_oXmlStyle.WriteLiteRStyle(oSettingStyle); + // sRSettings = m_oXmlStyle.GetStyle(); + // m_oXmlStyle.Clear(); + // } + + std::wstring wsFontSize; + + const int nCalculatedFontChange{CalculateFontChange(arSelectors)}; + + if (0 != nCalculatedFontChange) + { + int nFontSizeLevel{static_cast((pMainStyle->m_oFont.Empty()) ? 3 : GetFontSizeLevel(pMainStyle->m_oFont.GetSize().ToInt(NSCSS::Point) * 2))}; + + nFontSizeLevel += nCalculatedFontChange; + + const UINT unFontSize{GetFontSizeByLevel(nFontSizeLevel)}; + + wsFontSize += L""; + } + + const std::wstring wsTextMode{pMainStyle->m_oDisplay.GetVAlign().ToWString()}; + + if (!sRStyle.empty() || L"normal" != wsTextMode || !wsFontSize.empty() || !sRSettings.empty()) + { + oXml.WriteString(L""); + if (!sRStyle.empty()) + { + oXml.WriteString(L""); + } + + if (L"sub" == wsTextMode) + oXml.WriteString(L""); + else if (L"super" == wsTextMode) + oXml.WriteString(L""); + + oXml.WriteString(sRSettings + wsFontSize); + oXml.WriteString(L""); + } + return sRStyle; +} + +bool CHTML2OOXMLInterpretator::WriteText(const std::wstring& wsText, const std::vector& arSelectors) +{ + if (wsText.empty()) + return false; + + std::wstring wsNormalizeText(wsText); + + bool bBidirectional{false}, bPreformatted{false}, bQuotation{false}, bAddSpaces{true}, bMergedText{false}; + + for (const NSCSS::CNode& oNode : arSelectors) + { + if (L"bdo" == oNode.m_wsName && L"rtl" == oNode.GetAttributeValue(L"dir")) + bBidirectional = true; + else if (L"bdi" == oNode.m_wsName) + bBidirectional = false; + else if (L"pre" == oNode.m_wsName || L"nobr" == oNode.m_wsName || L"xmp" == oNode.m_wsName) + bPreformatted = true; + else if (L"q" == oNode.m_wsName) + bQuotation = true; + else if (L"span" == oNode.m_wsName) + bAddSpaces = false; + } + + const NSCSS::CCompiledStyle* pCompiledStyle{arSelectors.back().m_pCompiledStyle}; + + if (!bPreformatted && nullptr != arSelectors.back().m_pCompiledStyle) + { + // TODO::поведение должно быть немного разное (реализовать) + switch(pCompiledStyle->m_oDisplay.GetWhiteSpace().ToInt()) + { + case NSCSS::NSProperties::EWhiteSpace::Pre: + case NSCSS::NSProperties::EWhiteSpace::Pre_Wrap: + case NSCSS::NSProperties::EWhiteSpace::Pre_Line: + bPreformatted = true; + default: + break; + } + } + + if (!bPreformatted && wsNormalizeText.end() == std::find_if_not(wsNormalizeText.begin(), wsNormalizeText.end(), [](wchar_t wchChar){ return iswspace(wchChar) && 0xa0 != wchChar;})) + return false; + + std::wstring wsHeaderId; + + if (ElementInHeader(arSelectors)) + wsHeaderId = StandardizeHeaderId(wsNormalizeText); + + if(bBidirectional) + std::reverse(wsNormalizeText.begin(), wsNormalizeText.end()); + + const bool bInT = m_oState.m_bInT; + + //TODO:: сделать так, чтобы параграф (со своими стилями) открывался при чтении сооответствующей ноды, а не при чтении текста + OpenP(); + + WritePPr(arSelectors); + + std::wstring wsCrossId; + + if (!wsHeaderId.empty()) + WriteEmptyBookmark(wsHeaderId); + + NSStringUtils::CStringBuilder oRPr; + std::wstring sRStyle; + + if (OpenR()) + { + sRStyle = WriteRPr(oRPr, arSelectors); + WriteToStringBuilder(oRPr, *m_pCurrentDocument); + } + + if (bQuotation) + m_pCurrentDocument->WriteString(L"""); + + if (!bPreformatted && bAddSpaces && m_oState.m_bInP && !m_oState.m_bInR && !iswspace(wsNormalizeText.front()) && !iswpunct(wsNormalizeText.front()) && !m_oState.m_bWasSpace) + { + if (pCompiledStyle->m_oDisplay.GetVAlign().Empty() || L"normal" == pCompiledStyle->m_oDisplay.GetVAlign().ToWString()) + WriteSpace(); + } + + if(bPreformatted) + { + size_t unBegin = 0, unEnd = wsNormalizeText.find_first_of(L"\n\r\t"); + + while (std::wstring::npos != unBegin) + { + if (OpenR()) + WriteToStringBuilder(oRPr, *m_pCurrentDocument); + + OpenT(); + if (unEnd == std::wstring::npos) + { + m_pCurrentDocument->WriteEncodeXmlString(wsNormalizeText.c_str() + unBegin, wsNormalizeText.length() - unBegin); + break; + } + + if (unBegin != unEnd) + { + m_pCurrentDocument->WriteEncodeXmlString(wsNormalizeText.c_str() + unBegin, unEnd - unBegin); + CloseT(); + } + + if (L'\n' == wsNormalizeText[unEnd]) + m_pCurrentDocument->WriteString(L""); + else if (L'\t' == wsNormalizeText[unEnd]) + m_pCurrentDocument->WriteString(L""); + + unBegin = unEnd + 1; + unEnd = wsNormalizeText.find_first_of(L"\n\r\t", unBegin); + } + } + else + { + ReplaceSpaces(wsNormalizeText); + + if (!wsNormalizeText.empty() && L'\t' == wsNormalizeText[0]) + { + m_pCurrentDocument->WriteString(L""); + wsNormalizeText.erase(0, 1); + } + + if (!wsNormalizeText.empty() && std::iswspace(wsNormalizeText.front()) && m_oState.m_bWasSpace) + wsNormalizeText.erase(0, 1); + + OpenT(); + + if (bMergedText && !m_oState.m_bWasSpace && bInT && !bPreformatted) + m_pCurrentDocument->WriteEncodeXmlString(L" "); + + if (!wsNormalizeText.empty()) + { + m_oState.m_bWasSpace = std::iswspace(wsNormalizeText.back()); + m_pCurrentDocument->WriteEncodeXmlString(wsNormalizeText); + } + } + + if (bQuotation) + m_pCurrentDocument->WriteString(L"""); + + CloseT(); + + if (!bMergedText) + CloseR(); + + return true; +} + +void CHTML2OOXMLInterpretator::WriteBr(std::vector& arSelectors) +{ + if (m_oState.m_bInP) + { + OpenR(); + if(arSelectors.back().m_pCompiledStyle->m_oText.GetAlign() == L"both") + m_pCurrentDocument->WriteString(L""); + m_pCurrentDocument->WriteString(L""); + CloseR(); + } + else + WriteEmptyParagraph(false, m_oState.m_bInP); + + m_oState.m_bWasSpace = true; +} + void CHTML2OOXMLInterpretator::WriteEmptyParagraph(bool bVahish, bool bInP) { if (!bInP) @@ -240,6 +855,26 @@ void CHTML2OOXMLInterpretator::WriteEmptyParagraph(bool bVahish, bool bInP) m_pCurrentDocument->WriteString(L""); } +void CHTML2OOXMLInterpretator::WriteSpace() +{ + OpenR(); + m_pCurrentDocument->WriteString(L" "); + CloseR(); + m_oState.m_bWasSpace = true; +} + +void CHTML2OOXMLInterpretator::WriteEmptyBookmark(const std::wstring& wsId) +{ + const std::wstring wsCrossId{WriteBookmark(wsId)}; + + if (wsCrossId.empty()) + return; + + m_pCurrentDocument->WriteString(L"WriteString(wsCrossId); + m_pCurrentDocument->WriteString(L"\"/>"); +} + std::wstring CHTML2OOXMLInterpretator::WriteBookmark(const std::wstring& wsId) { const std::wstring sCrossId = std::to_wstring(m_mBookmarks.size() + 1); @@ -290,6 +925,11 @@ std::wstring CHTML2OOXMLInterpretator::GetStyle(const NSCSS::CCompiledStyle& oSt return m_oXmlStyle.GetIdAndClear(); } +CTextSettings& CHTML2OOXMLInterpretator::GetTextSettings() +{ + return m_oTextSettings; +} + XmlString& CHTML2OOXMLInterpretator::GetStylesXml() { return m_oStylesXml; @@ -339,4 +979,229 @@ 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; }); } + +inline void WriteToStringBuilder(NSStringUtils::CStringBuilder& oSrcStringBuilder, NSStringUtils::CStringBuilder& oDstStringBuilder) +{ + if (oSrcStringBuilder.GetCurSize() < MAX_STRING_BLOCK_SIZE) + { + oDstStringBuilder.Write(oSrcStringBuilder); + return; + } + + size_t ulSize = oSrcStringBuilder.GetCurSize(); + size_t ulCurrentBlockSize = 0, ulPosition = 0; + + while (ulSize > 0) + { + ulCurrentBlockSize = std::min(ulSize, MAX_STRING_BLOCK_SIZE); + oDstStringBuilder.WriteString(oSrcStringBuilder.GetSubData(ulPosition, ulCurrentBlockSize)); + + ulSize -= ulCurrentBlockSize; + ulPosition += ulCurrentBlockSize; + } +} + +inline bool ElementInHeader(const std::vector arSelsectors) +{ + for (const NSCSS::CNode& oNode : arSelsectors) + { + if (2 == oNode.m_wsName.length() && L'h' != oNode.m_wsName[0] && + (L'1' == oNode.m_wsName[1] || L'2' == oNode.m_wsName[1] || + L'3' == oNode.m_wsName[1] || L'4' == oNode.m_wsName[1] || + L'5' == oNode.m_wsName[1] || L'6' == oNode.m_wsName[1])) + return true; + } + + return false; +} + +std::wstring StandardizeHeaderId(const std::wstring& wsHeader) +{ + if (wsHeader.empty()) + return std::wstring(); + + std::wstring result; + result.reserve(wsHeader.size()); + + // Флаг, указывающий, был ли предыдущий символ дефисом + bool prevWasHyphen = false; + bool inWhitespaceSequence = false; + wchar_t lowerC; + + for (wchar_t c : wsHeader) + { + // Приведение к нижнему регистру + lowerC = std::tolower(c); + + // Проверяем, является ли символ буквой или цифрой + if (std::iswalnum(lowerC)) + { + result.push_back(lowerC); + prevWasHyphen = false; + inWhitespaceSequence = false; + } + // Проверяем, является ли символ пробельным (пробел, табуляция и т.д.) + else if (std::iswspace(lowerC)) + { + // Заменяем последовательности пробельных символов на один дефис + if (!inWhitespaceSequence && !result.empty()) + { + result.push_back(L'-'); + inWhitespaceSequence = true; + } + } + // Проверяем, является ли символ дефисом или подчеркиванием + else if (c == L'-' || c == L'_') + { + // Добавляем дефис, если предыдущий символ не был дефисом + if (!prevWasHyphen && !result.empty()) + { + result.push_back(L'-'); + prevWasHyphen = true; + } + inWhitespaceSequence = false; + } + // Все остальные символы (знаки препинания) пропускаем + // Но если это буква в Unicode, мы можем её обработать + else if (std::iswalpha(lowerC)) + { + // Для Unicode-символов, которые являются буквами + result.push_back(lowerC); + prevWasHyphen = false; + inWhitespaceSequence = false; + } + // Остальные символы игнорируем + } + + // Удаляем дефисы в начале и конце + size_t start = 0; + size_t end = result.length(); + + while (start < end && result[start] == L'-') + ++start; + + while (end > start && result[end - 1] == L'-') + --end; + + // Удаляем последовательные дефисы + std::wstring finalResult; + finalResult.reserve(end - start); + + bool lastWasHyphen = false; + for (size_t i = start; i < end; i++) + { + if (result[i] == L'-') + { + if (!lastWasHyphen) + { + finalResult.push_back(L'-'); + lastWasHyphen = true; + } + } + else + { + finalResult.push_back(result[i]); + lastWasHyphen = false; + } + } + + return finalResult; +} + +inline int CalculateFontChange(const std::vector& arSelectors) +{ + int nFontChange = 0; + + for (const NSCSS::CNode& oNode : arSelectors) + { + if (L"big" == oNode.m_wsName) + ++nFontChange; + else if (L"small" == oNode.m_wsName) + --nFontChange; + } + + return nFontChange; +} + +inline UINT GetFontSizeLevel(UINT unFontSize) +{ + if (unFontSize <= 18) + return 1; + else if (unFontSize <= 22) + return 2; + else if (unFontSize <= 26) + return 3; + else if (unFontSize <= 30) + return 4; + else if (unFontSize <= 40) + return 5; + else if (unFontSize <= 59) + return 6; + else + return 7; +} + +inline UINT GetFontSizeByLevel(UINT unLevel) +{ + if (0 == unLevel) + return 15; + else if (unLevel > 7) + return 72; + + switch (unLevel) + { + case 1: return 15; + case 2: return 20; + case 3: return 24; + case 4: return 27; + case 5: return 36; + case 6: return 48; + case 7: return 72; + } + return 24; +} + +inline void ReplaceSpaces(std::wstring& wsValue) +{ + // boost::wregex oRegex(L"\\s+"); + // wsValue = boost::regex_replace(wsValue, oRegex, L" "); + + std::wstring::const_iterator itBegin = std::find_if(wsValue.cbegin(), wsValue.cend(), [](wchar_t wchValue){ return std::iswspace(wchValue) && 0xa0 != wchValue; }); + std::wstring::const_iterator itEnd; + + while (wsValue.cend() != itBegin) + { + itEnd = std::find_if(itBegin, wsValue.cend(), [](wchar_t wchValue){ return !std::iswspace(wchValue) || 0xa0 == wchValue; }); + + wsValue.replace(itBegin, itEnd, L" "); + + itBegin = std::find_if(itBegin + 1, wsValue.cend(), [](wchar_t wchValue){ return std::iswspace(wchValue) && 0xa0 != wchValue; }); + } +} + +inline void ReplaceAll(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); + } +} + +inline std::wstring EncodeXmlString(std::wstring wsString) +{ + ReplaceAll(wsString, L"&", L"&"); + ReplaceAll(wsString, L"<", L"<"); + ReplaceAll(wsString, L">", L">"); + ReplaceAll(wsString, L"\"", L"""); + ReplaceAll(wsString, L"\'", L"'"); + ReplaceAll(wsString, L"\n", L" "); + ReplaceAll(wsString, L"\r", L" "); + ReplaceAll(wsString, L"\t", L" "); + + return wsString; +} } diff --git a/HtmlFile2/HTML2OOXMLInterpretator.h b/HtmlFile2/HTML2OOXMLInterpretator.h index 881549007b..8563ae4a1d 100644 --- a/HtmlFile2/HTML2OOXMLInterpretator.h +++ b/HtmlFile2/HTML2OOXMLInterpretator.h @@ -5,7 +5,6 @@ #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" @@ -25,7 +24,8 @@ class CHTML2OOXMLInterpretator : public IHTMLInterpretator XmlString *m_pCurrentDocument; //Текущее место записи - NSCSS::CDocumentStyle m_oXmlStyle; // Ooxml стиль + NSCSS::CDocumentStyle m_oXmlStyle; // Ooxml стиль + NSCSS::NSProperties::CPage m_oPageData; // Стили страницы struct TState { @@ -47,6 +47,8 @@ class CHTML2OOXMLInterpretator : public IHTMLInterpretator {} } m_oState; + CTextSettings m_oTextSettings; + int m_nFootnoteId; // ID сноски int m_nHyperlinkId; // ID ссылки int m_nNumberingId; // ID списка @@ -56,10 +58,14 @@ class CHTML2OOXMLInterpretator : public IHTMLInterpretator std::map m_mFootnotes; // Сноски std::map m_mBookmarks; // Закладки using anchors_map = std::map; - anchors_map m_mAnchors; // Map якорей с индивидуальными id + anchors_map m_mAnchors; // Map якорей с индивидуальными id + std::map m_mDivs; // Div элементы public: CHTML2OOXMLInterpretator(); + void Begin(const std::wstring& wsDst, const THtmlParams* pParams) override; + void End(const std::wstring& wsDst) override; + bool OpenP(); bool OpenR(); bool OpenT(); @@ -68,21 +74,34 @@ public: 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 BeginBlock(std::vector& arSelectors) override; + void EndBlock(bool bAddBlock, std::vector& arSelectors) override; + + void OpenCrossHyperlink(const std::wstring& wsRef, std::vector& arSelectors); + void OpenExternalHyperlink(const std::wstring& wsRef, const std::wstring& wsTooltip, std::vector& arSelectors); void CloseCrossHyperlink(std::vector& arSelectors, std::wstring wsFootnote, const std::wstring& wsRef); void CloseExternalHyperlink(); - std::wstring WritePPr(std::vector& arSelectors, CTextSettings& oTS); + void OpenFldChar(const std::wstring& wsNote); + void CloseFldChar(); + std::wstring WritePPr(const std::vector& arSelectors); + std::wstring WriteRPr(XmlString& oXml, const std::vector& arSelectors); + + bool WriteText(const std::wstring& wsText, const std::vector& arSelectors) override; + void WriteBr(std::vector& arSelectors); void WriteEmptyParagraph(bool bVahish = false, bool bInP = false) override; + void WriteSpace(); + void WriteEmptyBookmark(const std::wstring& wsId); std::wstring WriteBookmark(const std::wstring& wsId); std::wstring AddAnchor(const std::wstring& wsAnchorValue); std::wstring GetStyle(const NSCSS::CCompiledStyle& oStyle, bool bParagraphStyle); + CTextSettings& GetTextSettings(); + XmlString& GetStylesXml(); XmlString& GetDocRelsXml(); XmlString& GetNotesRelsXml(); diff --git a/HtmlFile2/HTMLInterpretator.h b/HtmlFile2/HTMLInterpretator.h index b54fe19f50..1db5ff8725 100644 --- a/HtmlFile2/HTMLInterpretator.h +++ b/HtmlFile2/HTMLInterpretator.h @@ -1,6 +1,9 @@ #ifndef HTMLINTERPRETATOR_H #define HTMLINTERPRETATOR_H +#include "../Common/3dParty/html/css/src/CNode.h" +#include "HTMLParams.h" + namespace HTML { class IHTMLInterpretator @@ -9,49 +12,19 @@ public: IHTMLInterpretator() = default; virtual ~IHTMLInterpretator() = default; + virtual void Begin(const std::wstring& wsDst, const THtmlParams* pParams) = 0; + virtual void End(const std::wstring& wsDst) = 0; + + virtual bool WriteText(const std::wstring& wsText, const std::vector& arSelectors) = 0; + virtual void WriteEmptyParagraph(bool bVahish = false, bool bInP = false) = 0; + virtual void BeginBlock(std::vector& arSelectors) = 0; + virtual void EndBlock(bool bAddBlock, std::vector& arSelectors) = 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; }; } diff --git a/HtmlFile2/HTMLParams.h b/HtmlFile2/HTMLParams.h new file mode 100644 index 0000000000..623a628417 --- /dev/null +++ b/HtmlFile2/HTMLParams.h @@ -0,0 +1,69 @@ +#ifndef HTMLPARAMS_H +#define HTMLPARAMS_H + +#include + +namespace HTML +{ +struct THtmlParams +{ + std::wstring m_sGenres; // Жанры + std::wstring m_sAuthors; // Авторы + std::wstring m_sBookTitle; // Название + std::wstring m_sDate; // Дата + std::wstring m_sDescription; // описание + std::wstring m_sLanguage; // Язык + bool m_bNeedPageBreakBefore; // Новый html с новой страницы + std::wstring m_sdocDefaults; // Стиль docDefaults + std::wstring m_sNormal; // Стиль normal + + THtmlParams() : m_bNeedPageBreakBefore(false) {} + + void SetNormal(const std::wstring& sStyle) + { + m_sNormal = sStyle; + } + + void SetDocDefaults(const std::wstring& sStyle) + { + m_sdocDefaults = sStyle; + } + + void SetPageBreakBefore(bool bNeed) + { + m_bNeedPageBreakBefore = bNeed; + } + + void SetDate(const std::wstring& sDate) + { + m_sDate = sDate; + } + + void SetDescription(const std::wstring& sDescription) + { + m_sDescription = sDescription; + } + + void SetGenres(const std::wstring& sGenres) + { + m_sGenres = sGenres; + } + + void SetAuthors(const std::wstring& sAuthors) + { + m_sAuthors = sAuthors; + } + + void SetTitle(const std::wstring& sTitle) + { + m_sBookTitle = sTitle; + } + + void SetLanguage(const std::wstring& sLanguage) + { + m_sLanguage = sLanguage; + } +}; +} + +#endif // HTMLPARAMS_H diff --git a/HtmlFile2/HTMLReader.cpp b/HtmlFile2/HTMLReader.cpp index e0aeab33bb..9b6b660146 100644 --- a/HtmlFile2/HTMLReader.cpp +++ b/HtmlFile2/HTMLReader.cpp @@ -6,9 +6,6 @@ #include "Common.h" #include "Tags/HTMLTags2OOXML.h" -#include "../Common/3dParty/html/gumbo-parser/src/gumbo.h" -#include -#include namespace HTML { @@ -17,8 +14,6 @@ namespace HTML #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), @@ -159,10 +154,34 @@ inline HtmlTag GetHtmlTag(const std::wstring& wsStrTag); inline bool UnreadableNode(const std::wstring& wsNodeName); inline bool TagIsUnprocessed(const std::wstring& wsTagName); +#define ADD_OOXML_TAG(tag_name, struct_name)\ + m_mTags[HTML_TAG(tag_name)] = new struct_name((CHTML2OOXMLInterpretator*)m_pInterpretator) + +#define ADD_EMPTY_OOXML_TAG(tag_name, struct_name)\ + m_mTags[HTML_TAG(tag_name)] = new struct_name() + CHTMLReader::CHTMLReader() : m_pInterpretator(new CHTML2OOXMLInterpretator()) { - m_mTags[HTML_TAG(A)] = new TAnchor((CHTML2OOXMLInterpretator*)m_pInterpretator); + ADD_EMPTY_OOXML_TAG(B, TBold); + ADD_EMPTY_OOXML_TAG(BR, TCenter); + ADD_EMPTY_OOXML_TAG(I, TItalic); + ADD_EMPTY_OOXML_TAG(CODE, TCode); + ADD_EMPTY_OOXML_TAG(S, TStrike); + ADD_EMPTY_OOXML_TAG(U, TUnderline); + ADD_EMPTY_OOXML_TAG(MARK, TMark); + ADD_EMPTY_OOXML_TAG(SUP, TSup); + ADD_EMPTY_OOXML_TAG(SUB, TSub); + ADD_EMPTY_OOXML_TAG(DD, TDD); + ADD_EMPTY_OOXML_TAG(H1, THeader); + + ADD_OOXML_TAG(A, TAnchor); + ADD_OOXML_TAG(ABBR, TAbbr); + ADD_OOXML_TAG(BR, TBr); + ADD_OOXML_TAG(BDO, TBidirectional); + ADD_OOXML_TAG(Q, TQuotation); + ADD_OOXML_TAG(SPAN, TSpan); + ADD_OOXML_TAG(PRE, TPreformatted); } CHTMLReader::~CHTMLReader() @@ -171,12 +190,14 @@ CHTMLReader::~CHTMLReader() delete m_pInterpretator; } -HRESULT CHTMLReader::ReadFromFile(const std::wstring& wsFileName) +HRESULT CHTMLReader::ConvertFromTo(const std::wstring& wsFrom, const std::wstring& wsTo) { - if (!HTML2XHTML(wsFileName) || !m_oLightReader.IsValid() || !IsHTML()) + if (nullptr == m_pInterpretator || !HTML2XHTML(wsFrom) || !m_oLightReader.IsValid() || !IsHTML()) return S_FALSE; - m_sSrc = NSSystemPath::GetDirectoryName(wsFileName); + m_pInterpretator->Begin(wsTo, nullptr); + + m_sSrc = NSSystemPath::GetDirectoryName(wsFrom); // m_sDst = sDst; ReadStyle(); @@ -189,6 +210,8 @@ HRESULT CHTMLReader::ReadFromFile(const std::wstring& wsFileName) // m_internal->PageBreakBefore(); ReadDocument(); + + m_pInterpretator->End(wsTo); return S_OK; } @@ -393,19 +416,20 @@ void CHTMLReader::ReadBody() m_oLightReader.MoveToElement(); */ - CTextSettings oTS; - ReadStream(arSelectors, oTS); + ReadStream(arSelectors); } -bool CHTMLReader::ReadStream(std::vector& arSelectors, CTextSettings& oTS, bool bInsertEmptyP) +bool CHTMLReader::ReadStream(std::vector& arSelectors, 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; + if (!bInsertEmptyP) + return false; + + m_pInterpretator->WriteEmptyParagraph(true, true); + return true; + // WriteEmptyParagraph(sSelectors, oTS); // if (bInsertEmptyP) // { @@ -422,32 +446,23 @@ bool CHTMLReader::ReadStream(std::vector& arSelectors, CTextSettin do { - if (ReadInside(arSelectors, oTS)) + if (ReadInside(arSelectors)) 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) +bool CHTMLReader::ReadInside(std::vector& arSelectors) { const std::wstring wsName{m_oLightReader.GetName()}; //TODO:: обработать все варианты return'а - // if(wsName == L"#text") - // return m_pInterpretator->ReadText(oXml, arSelectors, oTS); + if(wsName == L"#text") + return ReadText(arSelectors); if (UnreadableNode(wsName) || TagIsUnprocessed(wsName)) return false; @@ -463,74 +478,64 @@ bool CHTMLReader::ReadInside(std::vector& arSelectors, CTextSettin case HTML_TAG(A): case HTML_TAG(AREA): { - bResult = ReadA(arSelectors, oTS); + bResult = ReadA(arSelectors); break; } - default: + case HTML_TAG(ABBR): + { + bResult = ReadDefaultTag(HTML_TAG(ABBR), arSelectors); 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(B): + case HTML_TAG(STRONG): + { + bResult = ReadDefaultTag(HTML_TAG(B), arSelectors); + break; + } + case HTML_TAG(BDO): + case HTML_TAG(BDI): + { + bResult = ReadDefaultTag(HTML_TAG(BDO), arSelectors); + break; + } + case HTML_TAG(BR): + { + bResult = ReadBr(arSelectors); + break; + } + case HTML_TAG(CENTER): + { + bResult = ReadDefaultTag(HTML_TAG(CENTER), arSelectors); + break; + } + case HTML_TAG(CITE): + case HTML_TAG(DFN): + case HTML_TAG(EM): + case HTML_TAG(I): + case HTML_TAG(VAR): + { + bResult = ReadDefaultTag(HTML_TAG(I), arSelectors); + break; + } + case HTML_TAG(CODE): + case HTML_TAG(SAMP): + case HTML_TAG(TT): + { + bResult = ReadDefaultTag(HTML_TAG(CODE), arSelectors); + break; + } + case HTML_TAG(KBD): + { + bResult = ReadDefaultTag(HTML_TAG(KBD), arSelectors); + break; + } + case HTML_TAG(DEL): + case HTML_TAG(S): + case HTML_TAG(STRIKE): + { + bResult = ReadDefaultTag(HTML_TAG(S), arSelectors); + break; + } // case HTML_TAG(FONT): // { // bResult = m_pInterpretator->ReadFont(oXml, sSelectors, oTS); @@ -541,32 +546,32 @@ bool CHTMLReader::ReadInside(std::vector& arSelectors, CTextSettin // 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(INS): + case HTML_TAG(U): + { + bResult = ReadDefaultTag(HTML_TAG(U), arSelectors); + break; + } + case HTML_TAG(MARK): + { + bResult = ReadDefaultTag(HTML_TAG(MARK), arSelectors); + break; + } + case HTML_TAG(Q): + { + bResult = ReadDefaultTag(HTML_TAG(Q), arSelectors); + break; + } + case HTML_TAG(SUP): + { + bResult = ReadDefaultTag(HTML_TAG(SUP), arSelectors); + break; + } + case HTML_TAG(SUB): + { + bResult = ReadDefaultTag(HTML_TAG(SUB), arSelectors); + break; + } // case HTML_TAG(SVG): // { // m_pInterpretator->readSVG(oXml, sSelectors, oTS); @@ -584,76 +589,83 @@ bool CHTMLReader::ReadInside(std::vector& arSelectors, CTextSettin // 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(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): + { + //Если встретили не обрабатываемые теги, то просто пропускаем + arSelectors.pop_back(); + return false; + } + case HTML_TAG(SPAN): + { + bResult = ReadDefaultTag(HTML_TAG(SPAN), arSelectors); + break; + } + case HTML_TAG(NOBR): + { + bResult = ReadDefaultTag(HTML_TAG(PRE), arSelectors); + 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}; + 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 = ReadStream(arSelectors); + break; + } + default: + { + m_pInterpretator->BeginBlock(arSelectors); - // 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; - // } + switch(eHtmlTag) + { + case HTML_TAG(ADDRESS): + { + bResult = ReadDefaultTag(HTML_TAG(I), arSelectors); + break; + } + case HTML_TAG(DD): + { + bResult = ReadDefaultTag(HTML_TAG(DD), arSelectors); + break; + } + 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 = ReadDefaultTag(HTML_TAG(H1), arSelectors); + break; + } // case HTML_TAG(ASIDE): // case HTML_TAG(DIV): // { @@ -715,12 +727,12 @@ bool CHTMLReader::ReadInside(std::vector& arSelectors, CTextSettin // 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(PRE): + case HTML_TAG(XMP): + { + bResult = ReadDefaultTag(HTML_TAG(PRE), arSelectors); + break; + } // case HTML_TAG(TABLE): // { // bResult = ParseTable(&oXmlData, sSelectors, oTS); @@ -742,22 +754,15 @@ bool CHTMLReader::ReadInside(std::vector& arSelectors, CTextSettin // bResult = ReadDetails(&oXmlData, sSelectors, oTS); // break; // } - // default: - // { - // bResult = readStream(&oXmlData, sSelectors, oTS); - // break; - // } - // } + default: + { + bResult = ReadStream(arSelectors); + break; + } + } - // readNote(&oXmlData, sSelectors, sNote); - - // CloseP(&oXmlData, sSelectors); - - // if (bResult) - // WriteToStringBuilder(oXmlData, *oXml); - // else - // m_oState = oCurentState; - // } + m_pInterpretator->EndBlock(bResult, arSelectors); + } } // if (HTML_TAG(DIV) != eHtmlTag && HTML_TAG(ASIDE) != eHtmlTag) @@ -773,24 +778,57 @@ bool CHTMLReader::ReadInside(std::vector& arSelectors, CTextSettin return bResult; } -bool CHTMLReader::ReadA(std::vector& arSelectors, CTextSettings& oTS) +bool CHTMLReader::ReadText(std::vector& arSelectors) { - if (!m_mTags[HTML_TAG(A)]->Open(arSelectors, oTS)) + if (nullptr == m_pInterpretator) return false; - if(!ReadStream(arSelectors, oTS)) + GetSubClass(arSelectors); + + const bool bResult{m_pInterpretator->WriteText(m_oLightReader.GetText(), arSelectors)}; + + arSelectors.pop_back(); + + return bResult; +} + +bool CHTMLReader::ReadA(std::vector& arSelectors) +{ + if (!m_mTags[HTML_TAG(A)]->Open(arSelectors)) + return false; + + if(!ReadStream(arSelectors)) m_pInterpretator->WriteEmptyParagraph(true); m_mTags[HTML_TAG(A)]->Close(arSelectors); - #ifdef _DEBUG - m_pInterpretator->PrintData(); - #endif + return true; +} + +bool CHTMLReader::ReadBr(std::vector& arSelectors) +{ + if (!m_mTags[HTML_TAG(BR)]->Open(arSelectors)) + return false; + + m_mTags[HTML_TAG(BR)]->Close(arSelectors); return true; } -void CHTMLReader::GetSubClass(std::vector& sSelectors) + +bool CHTMLReader::ReadDefaultTag(HtmlTag eTag, std::vector& arSelectors) +{ + if (!m_mTags[eTag]->Open(arSelectors)) + return false; + + const bool bResult = ReadStream(arSelectors); + + m_mTags[eTag]->Close(arSelectors); + + return bResult; +} + +void CHTMLReader::GetSubClass(std::vector& arSelectors) { NSCSS::CNode oNode; @@ -818,9 +856,9 @@ void CHTMLReader::GetSubClass(std::vector& sSelectors) } } m_oLightReader.MoveToElement(); - sSelectors.push_back(oNode); + arSelectors.push_back(oNode); - m_oStylesCalculator.CalculateCompiledStyle(sSelectors); + m_oStylesCalculator.CalculateCompiledStyle(arSelectors); } inline std::wstring GetArgumentValue(XmlUtils::CXmlLiteReader& oLiteReader, const std::wstring& wsArgumentName, const std::wstring& wsDefaultValue) diff --git a/HtmlFile2/HTMLReader.h b/HtmlFile2/HTMLReader.h index 560b46fba0..b0a86f99fc 100644 --- a/HtmlFile2/HTMLReader.h +++ b/HtmlFile2/HTMLReader.h @@ -7,15 +7,17 @@ #include "HTMLInterpretator.h" #include "Tags/HTMLTags.h" +#include "../Common/3dParty/html/gumbo-parser/src/gumbo.h" + namespace HTML { +#define HtmlTag GumboTag + 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; // Директория назначения @@ -29,7 +31,7 @@ public: CHTMLReader(); ~CHTMLReader(); - HRESULT ReadFromFile(const std::wstring& wsFileName); + HRESULT ConvertFromTo(const std::wstring& wsFrom, const std::wstring& wsTo); private: bool IsHTML(); @@ -43,12 +45,16 @@ private: void ReadHead(); void ReadBody(); - bool ReadStream(std::vector& arSelectors, CTextSettings& oTS, bool bInsertEmptyP = false); - bool ReadInside(std::vector& arSelectors, CTextSettings& oTS); + bool ReadStream(std::vector& arSelectors, bool bInsertEmptyP = false); + bool ReadInside(std::vector& arSelectors); - bool ReadA(std::vector& arSelectors, CTextSettings& oTS); + bool ReadText(std::vector& arSelectors); + bool ReadA(std::vector& arSelectors); + bool ReadBr(std::vector& arSelectors); - void GetSubClass(std::vector& sSelectors); + bool ReadDefaultTag(HtmlTag eTag, std::vector& arSelectors); + + void GetSubClass(std::vector& arSelectors); }; } diff --git a/HtmlFile2/HtmlFile2.pro b/HtmlFile2/HtmlFile2.pro index 59ba70256f..a68bf52f97 100644 --- a/HtmlFile2/HtmlFile2.pro +++ b/HtmlFile2/HtmlFile2.pro @@ -41,6 +41,7 @@ HEADERS += htmlfile2.h \ Common.h \ HTML2OOXMLInterpretator.h \ HTMLInterpretator.h \ + HTMLParams.h \ HTMLReader.h \ Tags/HTMLTags.h \ Tags/HTMLTags2OOXML.h \ diff --git a/HtmlFile2/Tags/HTMLTags.h b/HtmlFile2/Tags/HTMLTags.h index c545b0fd26..a65c2601fc 100644 --- a/HtmlFile2/Tags/HTMLTags.h +++ b/HtmlFile2/Tags/HTMLTags.h @@ -2,17 +2,26 @@ #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 bool Open(std::vector& sSelectors) = 0; virtual void Close(std::vector& sSelectors) = 0; }; +struct TEmptyTag : public ITag +{ + virtual ~TEmptyTag() = default; + virtual bool Open(std::vector& sSelectors) + { + return true; + }; + virtual void Close(std::vector& sSelectors) {}; +}; + template struct TTag : public ITag { @@ -22,7 +31,7 @@ struct TTag : public ITag : m_pInterpretator(pInterpretator) {} virtual ~TTag() = default; - virtual bool Open(std::vector& sSelectors, CTextSettings& oTS) = 0; + virtual bool Open(std::vector& sSelectors) = 0; virtual void Close(std::vector& sSelectors) = 0; bool ValidInterpretator() const @@ -31,12 +40,33 @@ struct TTag : public ITag } }; -template -struct TAnchor : public TTag -{ - virtual bool Open(std::vector& sSelectors, CTextSettings& oTS) = 0; - virtual void Close(std::vector& sSelectors) = 0; -}; +#define CREATE_TAG(tag_name)\ +template\ +struct tag_name : public TTag\ +{\ + virtual bool Open(std::vector& sSelectors) = 0;\ + virtual void Close(std::vector& sSelectors) = 0;\ +} + +CREATE_TAG(TAnchor); +CREATE_TAG(TAbbr); +CREATE_TAG(TBold); +CREATE_TAG(TBidirectional); +CREATE_TAG(TBr); +CREATE_TAG(TCenter); +CREATE_TAG(TItalic); +CREATE_TAG(TCode); +CREATE_TAG(TKbd); +CREATE_TAG(TStrike); +CREATE_TAG(TUnderline); +CREATE_TAG(TMark); +CREATE_TAG(TQuotation); +CREATE_TAG(TSup); +CREATE_TAG(TSub); +CREATE_TAG(TSpan); +CREATE_TAG(TDD); +CREATE_TAG(TPreformatted); +CREATE_TAG(THeader); } diff --git a/HtmlFile2/Tags/HTMLTags2OOXML.h b/HtmlFile2/Tags/HTMLTags2OOXML.h index 3a39786426..5c62d95d3e 100644 --- a/HtmlFile2/Tags/HTMLTags2OOXML.h +++ b/HtmlFile2/Tags/HTMLTags2OOXML.h @@ -6,6 +6,8 @@ namespace HTML { +inline bool GetTitle(const std::vector& arSelectors, std::wstring& wsTitle); + template<> struct TAnchor : public TTag { @@ -13,69 +15,34 @@ struct TAnchor : public TTag : TTag(pInterpretator) {} - virtual bool Open(std::vector& arSelectors, CTextSettings& oTS) + virtual bool Open(std::vector& arSelectors) { if (!ValidInterpretator()) return false; - std::wstring wsRef; - std::wstring wsAlt; + std::wstring wsRef, wsAlt, wsName; bool bCross = false; - std::map& mAttributes(arSelectors.back().m_mAttributes); + if (arSelectors.back().GetAttributeValue(L"href", wsRef) && wsRef.find('#') != std::wstring::npos) + bCross = true; - std::map::const_iterator itFound = mAttributes.find(L"href"); + if (arSelectors.back().GetAttributeValue(L"name", wsName)) + m_pInterpretator->WriteBookmark(wsName); - 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; + arSelectors.back().GetAttributeValue(L"alt", wsAlt); std::wstring wsTooltip(wsRef); - itFound = mAttributes.find(L"title"); - - if (mAttributes.cend() != itFound) - wsTooltip = itFound->second; + GetTitle(arSelectors, wsTooltip); if (bCross) - m_pInterpretator->OpenCrossHyperlink(wsRef, arSelectors, oTS); + m_pInterpretator->OpenCrossHyperlink(wsRef, arSelectors); else - m_pInterpretator->OpenExternalHyperlink(wsRef, wsTooltip, arSelectors, oTS); + m_pInterpretator->OpenExternalHyperlink(wsRef, wsTooltip, arSelectors); return true; } + virtual void Close(std::vector& arSelectors) { if (!ValidInterpretator()) @@ -84,26 +51,22 @@ struct TAnchor : public TTag bool bCross = false; std::wstring wsFootnote; - std::map& mAttributes(arSelectors.back().m_mAttributes); - std::map::const_iterator itFound; + // 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")) + if (arSelectors.back().GetAttributeValue(L"epub:type", wsFootnote) && wsFootnote.find(L"noteref")) wsFootnote = L"href"; } std::wstring wsRef; - itFound = mAttributes.find(L"href"); - if (mAttributes.cend() != itFound) + if (arSelectors.back().GetAttributeValue(L"href", wsRef)) { - wsRef = itFound->second; - if(itFound->second.find('#') != std::wstring::npos) + if(wsRef.find('#') != std::wstring::npos) bCross = true; } @@ -118,6 +81,211 @@ struct TAnchor : public TTag m_pInterpretator->CloseExternalHyperlink(); } }; + +template<> +struct TAbbr : public TTag +{ + TAbbr(CHTML2OOXMLInterpretator* pInterpretator) + : TTag(pInterpretator) + {} + + virtual bool Open(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return false; + + std::wstring wsTitle; + + if (!GetTitle(arSelectors, wsTitle)) + return false; + + m_pInterpretator->WritePPr(arSelectors); + m_pInterpretator->OpenFldChar(wsTitle); + + return true; + } + + virtual void Close(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return; + + m_pInterpretator->CloseFldChar(); + } +}; + +template<> +struct TBr : public TTag +{ + TBr(CHTML2OOXMLInterpretator* pInterpretator) + : TTag(pInterpretator) + {} + + virtual bool Open(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return false; + + m_pInterpretator->WriteBr(arSelectors); + + return true; + } + + virtual void Close(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return; + } +}; + +template<> +struct TBidirectional : public TTag +{ + TBidirectional(CHTML2OOXMLInterpretator* pInterpretator) + : TTag(pInterpretator) + {} + + virtual bool Open(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return false; + + if (L"bdo" == arSelectors.back().m_wsName) + { + std::wstring wsDir; + + arSelectors.back().GetAttributeValue(L"dir", wsDir); + + m_pInterpretator->GetTextSettings().SetNewBidirectional(wsDir == L"rtl"); + } + else + //TODO:: по идее можно оптимизировать при условии, что и так false + //Но основная проблема в RollBackBdo + m_pInterpretator->GetTextSettings().SetNewBidirectional(false); + + return true; + } + + virtual void Close(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return; + + m_pInterpretator->GetTextSettings().RollBackBidirectional(); + } +}; + +template<> +struct TQuotation : public TTag +{ + TQuotation(CHTML2OOXMLInterpretator* pInterpretator) + : TTag(pInterpretator) + {} + + virtual bool Open(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return false; + + m_pInterpretator->GetTextSettings().SetNewQuotation(true); + + return true; + } + + virtual void Close(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return; + + m_pInterpretator->GetTextSettings().RollBackQuotation(); + } +}; + +template<> +struct TSpan : public TTag +{ + TSpan(CHTML2OOXMLInterpretator* pInterpretator) + : TTag(pInterpretator) + {} + + virtual bool Open(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return false; + + m_pInterpretator->GetTextSettings().SetNewAddSpaces(false); + + return true; + } + + virtual void Close(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return; + + m_pInterpretator->GetTextSettings().RollBackAddSpaces(); + } +}; + +template<> +struct TPreformatted : public TTag +{ + TPreformatted (CHTML2OOXMLInterpretator* pInterpretator) + : TTag(pInterpretator) + {} + + virtual bool Open(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return false; + + m_pInterpretator->GetTextSettings().SetNewPreformatted(false); + + return true; + } + + virtual void Close(std::vector& arSelectors) + { + if (!ValidInterpretator()) + return; + + m_pInterpretator->GetTextSettings().RollBackPreformatted(); + } +}; + +#define CREATE_EMPTY_TAG(tag_name)\ +template<>\ +struct tag_name : public TEmptyTag\ +{\ + tag_name(){}\ +} + +CREATE_EMPTY_TAG(TBold); +CREATE_EMPTY_TAG(TCenter); +CREATE_EMPTY_TAG(TItalic); +CREATE_EMPTY_TAG(TCode); +CREATE_EMPTY_TAG(TKbd); +CREATE_EMPTY_TAG(TStrike); +CREATE_EMPTY_TAG(TUnderline); +CREATE_EMPTY_TAG(TMark); +CREATE_EMPTY_TAG(TSup); +CREATE_EMPTY_TAG(TSub); +CREATE_EMPTY_TAG(TDD); +CREATE_EMPTY_TAG(THeader); + +inline bool GetTitle(const std::vector& arSelectors, std::wstring& wsTitle) +{ + if (arSelectors.empty()) + return false; + + const std::map::const_iterator itFound{arSelectors.back().m_mAttributes.find(L"title")}; + + if (arSelectors.back().m_mAttributes.cend() == itFound) + return false; + + wsTitle= itFound->second; + return true; +} } #endif // HTMLTAGS2OOXML_H diff --git a/HtmlFile2/TextSettings.h b/HtmlFile2/TextSettings.h index 7e71d9c90f..3a368f35d1 100644 --- a/HtmlFile2/TextSettings.h +++ b/HtmlFile2/TextSettings.h @@ -2,46 +2,53 @@ #define TEXTSETTINGS_H #include "../Common/3dParty/html/css/src/CCompiledStyle.h" +#include namespace HTML { // Настройки текста -struct CTextSettings +class CTextSettings { - bool bBdo; // Реверс текста - bool bPre; // Сохранение форматирования (Сохранение пробелов, табуляций, переносов строк) - bool bQ; // Цитата - bool bAddSpaces; // Добавлять пробелы перед текстом? - bool bMergeText; // Объединять подряд идущий текст в 1? - int nLi; // Уровень списка - bool bNumberingLi; // Является ли список нумерованным + std::stack m_arBidirectional;// Реверс текста + std::stack m_arPreformatted; // Сохранение форматирования (Сохранение пробелов, табуляций, переносов строк) + std::stack m_arQuotation; // Цитата + std::stack m_arAddSpaces; // Добавлять пробелы перед текстом? + std::stack m_arMergeText; // Объединять подряд идущий текст в 1? - std::wstring sPStyle; + std::wstring m_sPStyle; - enum ETextMode - { - Normal, - Superscript, - Subscript - } eTextMode; - - NSCSS::CCompiledStyle oAdditionalStyle; + NSCSS::CCompiledStyle m_oAdditionalStyle; +public: 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; + SetNewBidirectional(false); + SetNewPreformatted(false); + SetNewQuotation(false); + SetNewAddSpaces(true); } + + #define CREATE_METHODS_FROM_ELEMENT(element_name)\ + void SetNew##element_name(bool bValue)\ + {\ + m_ar##element_name.push(bValue);\ + }\ + \ + void RollBack##element_name()\ + {\ + if (m_ar##element_name.size() > 1)\ + m_ar##element_name.pop();\ + }\ + \ + bool Get##element_name() const\ + {\ + return m_ar##element_name.top();\ + } + + CREATE_METHODS_FROM_ELEMENT(Bidirectional) + CREATE_METHODS_FROM_ELEMENT(Preformatted) + CREATE_METHODS_FROM_ELEMENT(Quotation) + CREATE_METHODS_FROM_ELEMENT(AddSpaces) }; } diff --git a/HtmlFile2/htmlfile2.cpp b/HtmlFile2/htmlfile2.cpp index dff9f0253e..67bce4de9d 100644 --- a/HtmlFile2/htmlfile2.cpp +++ b/HtmlFile2/htmlfile2.cpp @@ -2565,7 +2565,7 @@ private: NSStringUtils::CStringBuilder oPPr; - const std::wstring sPStyle = wrP(&oPPr, arSelectors, oTS); + wrP(&oPPr, arSelectors, oTS); WriteToStringBuilder(oPPr, *pXml); @@ -2582,9 +2582,6 @@ private: sRStyle = wrRPr(&oRPr, arSelectors, oTS); WriteToStringBuilder(oRPr, *pXml); - - if (oTS.bQ) - pXml->WriteString(L"""); } if (oTS.bQ) @@ -2600,10 +2597,7 @@ private: while (std::wstring::npos != unBegin) { if (OpenR(pXml)) - { - pXml->WriteString(L""); WriteToStringBuilder(oRPr, *pXml); - } OpenT(pXml); if (unEnd == std::wstring::npos) @@ -2676,7 +2670,7 @@ private: wrP(pXml, arSelectors, oTS); const std::wstring wsName{L"Bookmark" + std::to_wstring(m_mBookmarks.size() + 1)}; m_mBookmarks.insert(std::make_pair(wsName, m_mBookmarks.size() + 1)); - pXml->WriteString(L"HYPERLINK \\l \"" + wsName + L"\" \\o \""); + pXml->WriteString(L"HYPERLINK \\l \"" + wsName + L"\" \\o \""); pXml->WriteEncodeXmlString(wsNote); pXml->WriteString(L"\""); pXml->WriteString(L""); @@ -2695,7 +2689,7 @@ private: return false; CTextSettings oTSR(oTS); - oTSR.oAdditionalStyle.m_oFont.SetWeight(L"bold", UINT_MAX, true); + // oTSR.oAdditionalStyle.m_oFont.SetWeight(L"bold", UINT_MAX, true); return readStream(pXml, arSelectors, oTSR); } @@ -3837,7 +3831,7 @@ private: CTextSettings oNewSettings{oTS}; const std::wstring wsHighlight{sSelectors.back().m_pCompiledStyle->m_oBackground.GetColor() - .EquateToColor({{{0, 0, 0}, L"black"}, {{0, 0, 255}, L"blue"}, {{0, 255, 255}, L"cyan"}, + .EquateToColor({{{0, 0, 0}, L"black"}, {{0, 0, 255}, L"blue"}, {{0, 255, 255}, L"cyan"}, {{0, 255, 0}, L"green"}, {{255, 0, 255}, L"magenta"}, {{255, 0, 0}, L"red"}, {{255, 255, 0}, L"yellow"}, {{255, 255, 255}, L"white"}, {{0, 0, 139}, L"darkBlue"}, {{0, 139, 139}, L"darkCyan"}, {{0, 100, 0}, L"darkGreen"}, {{139, 0, 139}, L"darkMagenta"}, @@ -5118,7 +5112,7 @@ HRESULT CHtmlFile2::OpenHtml(const std::wstring& sSrc, const std::wstring& sDst, { HTML::CHTMLReader oHTMLReader; - oHTMLReader.ReadFromFile(sSrc); + return oHTMLReader.ConvertFromTo(sSrc, sDst); if(!m_internal->m_oLightReader.IsValid()) if(!IsHtmlFile(sSrc))