diff --git a/DesktopEditor/xml/include/xmlutils.h b/DesktopEditor/xml/include/xmlutils.h index c78f899d84..d9de4ee6c3 100644 --- a/DesktopEditor/xml/include/xmlutils.h +++ b/DesktopEditor/xml/include/xmlutils.h @@ -206,6 +206,7 @@ namespace XmlUtils CXmlNode ReadNode(const wchar_t* strNodeName); CXmlNode ReadNode(const std::wstring& strNodeName); CXmlNode ReadNodeNoNS(const std::wstring& strNodeName); + CXmlNodes ReadNodesNoNS(const std::wstring& strNodeName); CXmlNode GetNode(const std::wstring& sName); CXmlNodes GetNodes(const std::wstring& sName); diff --git a/DesktopEditor/xml/src/xmldom.cpp b/DesktopEditor/xml/src/xmldom.cpp index 32f11c1a7e..2a8e04193d 100644 --- a/DesktopEditor/xml/src/xmldom.cpp +++ b/DesktopEditor/xml/src/xmldom.cpp @@ -559,6 +559,29 @@ namespace XmlUtils } return node; } + CXmlNodes CXmlNode::ReadNodesNoNS(const std::wstring& sName) + { + CXmlNodes oNodes; + if (IsValid()) + { + bool bGetAll = false; + if (L"*" == sName) + bGetAll = true; + int nCount = (int)m_pBase->m_nodes.size(); + for (int i = 0; i < nCount; ++i) + { + if (bGetAll || sName == GetNameNoNS(m_pBase->m_nodes[i]->m_sName)) + { + CXmlNode oNode; + CXmlNodeBase* pBase = m_pBase->m_nodes[i]; + oNode.SetBase(pBase); + oNodes.m_nodes.insert(oNodes.m_nodes.end(), oNode); + } + } + } + + return oNodes; + } CXmlNode CXmlNode::GetNode(const std::wstring& sName) { @@ -687,4 +710,4 @@ namespace XmlUtils return strNodeName; return strNodeName.substr(nFind + 1); } -} \ No newline at end of file +} diff --git a/HtmlFile/HtmlFile.cpp b/HtmlFile/HtmlFile.cpp index a1887ba5ce..b60b879794 100644 --- a/HtmlFile/HtmlFile.cpp +++ b/HtmlFile/HtmlFile.cpp @@ -1,5 +1,11 @@ #include "HtmlFile.h" #include "../DesktopEditor/common/File.h" +#include "../DesktopEditor/common/StringBuilder.h" +#include "../DesktopEditor/common/String.h" +#include "../DesktopEditor/xml/include/xmlutils.h" + +#include +#include #ifdef LINUX #include @@ -125,3 +131,237 @@ int CHtmlFile::Convert(const std::wstring& sXml, const std::wstring& sPathIntern NSFile::CFileBinary::Remove(sTempFileForParams); return nReturnCode; } + +///////////////////////////////////////////////////////////////// +// EPUB +///////////////////////////////////////////////////////////////// + +static std::vector ParseEpub(const std::wstring& sPackagePath, std::wstring& sMetaInfo) +{ + std::vector arHtmls; + + XmlUtils::CXmlNode oNodeRoot; + if (!oNodeRoot.FromXmlFile(sPackagePath)) + return arHtmls; + + XmlUtils::CXmlNode oNodeMeta = oNodeRoot.ReadNodeNoNS(L"metadata"); + if (oNodeMeta.IsValid()) + { + NSStringUtils::CStringBuilder oBuilder; + + std::wstring sTitle = oNodeMeta.ReadValueString(L"dc:title"); + std::wstring sCreator = oNodeMeta.ReadValueString(L"dc:creator"); + std::wstring sPublisher = oNodeMeta.ReadValueString(L"dc:publisher"); + std::wstring sLanguage = oNodeMeta.ReadValueString(L"dc:language"); + std::wstring sContributor = oNodeMeta.ReadValueString(L"dc:contributor"); + std::wstring sDescription = oNodeMeta.ReadValueString(L"dc:description"); + std::wstring sCoverage = oNodeMeta.ReadValueString(L"dc:coverage"); + + XmlUtils::CXmlNodes oMetaNodes = oNodeMeta.ReadNodesNoNS(L"meta"); + if (oMetaNodes.IsValid()) + { + int nCountMeta = oMetaNodes.GetCount(); + for (int i = 0; i < nCountMeta; ++i) + { + XmlUtils::CXmlNode oNodeTmp; + oMetaNodes.GetAt(i, oNodeTmp); + + std::wstring sName = oNodeTmp.GetAttribute(L"name"); + if (sName == L"cover") + sCoverage = L"1"; + } + } + + if (!sTitle.empty()) + { + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(sTitle.c_str(), (int)sTitle.length()); + oBuilder.WriteString(L""); + } + if (!sCreator.empty()) + { + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(sCreator.c_str(), (int)sCreator.length()); + oBuilder.WriteString(L""); + + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(sCreator.c_str(), (int)sCreator.length()); + oBuilder.WriteString(L""); + } + if (!sPublisher.empty()) + { + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(sPublisher.c_str(), (int)sPublisher.length()); + oBuilder.WriteString(L""); + } + if (!sLanguage.empty()) + { + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(sLanguage.c_str(), (int)sLanguage.length()); + oBuilder.WriteString(L""); + } + if (!sContributor.empty()) + { + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(sContributor.c_str(), (int)sContributor.length()); + oBuilder.WriteString(L""); + } + if (!sDescription.empty()) + { + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(sDescription.c_str(), (int)sDescription.length()); + oBuilder.WriteString(L""); + } + if (!sCoverage.empty()) + { + oBuilder.WriteString(L"1"); + } + + if (0 != oBuilder.GetCurSize()) + sMetaInfo = L"" + oBuilder.GetData() + L""; + } + + XmlUtils::CXmlNode oNodeSpine = oNodeRoot.ReadNodeNoNS(L"spine"); + if (!oNodeRoot.IsValid()) + return arHtmls; + + XmlUtils::CXmlNodes oNodesItemRef = oNodeSpine.ReadNodesNoNS(L"itemref"); + if (!oNodeSpine.IsValid()) + return arHtmls; + + std::vector sIds; + int nCountRefs = oNodesItemRef.GetCount(); + for (int i = 0; i < nCountRefs; ++i) + { + XmlUtils::CXmlNode oNodeTmp; + oNodesItemRef.GetAt(i, oNodeTmp); + + std::wstring sId = oNodeTmp.GetAttribute(L"idref"); + if (!sId.empty()) + sIds.push_back(sId); + } + + if (0 == sIds.size()) + return arHtmls; + + XmlUtils::CXmlNode oNodeManifest = oNodeRoot.ReadNodeNoNS(L"manifest"); + if (!oNodeRoot.IsValid()) + return arHtmls; + XmlUtils::CXmlNodes oNodesItems = oNodeManifest.ReadNodesNoNS(L"item"); + if (!oNodeManifest.IsValid()) + return arHtmls; + + size_t pos = sPackagePath.find_last_of((wchar_t)'/'); + std::wstring sPackagePathDir = sPackagePath; + if (std::wstring::npos != pos) + sPackagePathDir = sPackagePath.substr(0, pos + 1); + + std::map mapHtmls; + int nCountItems = oNodesItems.GetCount(); + for (int i = 0; i < nCountItems; ++i) + { + XmlUtils::CXmlNode oNodeTmp; + oNodesItems.GetAt(i, oNodeTmp); + + std::wstring sMime = oNodeTmp.GetAttribute(L"media-type"); + std::wstring sHRef = oNodeTmp.GetAttribute(L"href"); + +#if 0 + //Decode URL + sHRef.Replace(_T("%20"), _T(" ")); + sHRef.Replace(_T("%3B"), _T(";")); + sHRef.Replace(_T("%2C"), _T(",")); + sHRef.Replace(_T("%26"), _T("&")); + sHRef.Replace(_T("%3D"), _T("=")); + sHRef.Replace(_T("%2B"), _T("+")); + sHRef.Replace(_T("%24"), _T("$")); +#endif + + std::wstring sId = oNodeTmp.GetAttribute(L"id"); + if (!sMime.empty() && !sHRef.empty()) + mapHtmls.insert(std::pair(sId, sPackagePathDir + sHRef)); + } + + for (std::vector::iterator iter = sIds.begin(); iter != sIds.end(); iter++) + { + std::map::const_iterator i = mapHtmls.find(*iter); + if (i != mapHtmls.end()) + { + arHtmls.push_back(i->second); + } + } + + return arHtmls; +} + +int CHtmlFile::ConvertEpub(const std::wstring& sFolder, std::wstring& sMetaInfo, const std::wstring& sXmlPart, const std::wstring& sPathInternal) +{ + std::wstring sFolderWithSlash = sFolder; + NSStringExt::Replace(sFolderWithSlash, L"\\", L"/"); + + if (!sFolderWithSlash.empty()) + { + wchar_t c = sFolderWithSlash.c_str()[sFolderWithSlash.length() - 1]; + if (c != '/' && c != '\\') + sFolderWithSlash += L"/"; + } + + std::wstring sMimeType = L""; + if (!NSFile::CFileBinary::ReadAllTextUtf8(sFolderWithSlash + L"mimetype", sMimeType)) + return 1; + + if (sMimeType != L"application/epub+zip") + return 1; + + std::wstring sContainer = sFolderWithSlash + L"META-INF/container.xml"; + XmlUtils::CXmlNode oNodeContainer; + if (!oNodeContainer.FromXmlFile(sContainer)) + return 1; + + XmlUtils::CXmlNode oNodeRootFiles = oNodeContainer.ReadNodeNoNS(L"rootfiles"); + if (!oNodeRootFiles.IsValid()) + return 1; + + std::wstring sPackagePathXml; + + XmlUtils::CXmlNodes oNodesRootFile = oNodeRootFiles.ReadNodesNoNS(L"rootfile"); + if (!oNodeRootFiles.IsValid()) + return 1; + + int nCount = oNodesRootFile.GetCount(); + for (int i = 0; i < nCount; ++i) + { + XmlUtils::CXmlNode oNodeRF; + oNodesRootFile.GetAt(i, oNodeRF); + + std::wstring sMime = oNodeRF.GetAttribute(L"media-type"); + std::wstring sPackagePath = oNodeRF.GetAttribute(L"full-path"); + + if (!sPackagePath.empty() && L"application/oebps-package+xml" == sMime) + sPackagePathXml = sFolderWithSlash + sPackagePath; + } + + if (sPackagePathXml.empty()) + return 1; + + std::vector arHtmls = ParseEpub(sPackagePathXml, sMetaInfo); + if (arHtmls.size() == 0) + return 1; + + NSStringUtils::CStringBuilder oBuilder; + for (std::vector::iterator iter = arHtmls.begin(); iter != arHtmls.end(); iter++) + { + oBuilder.WriteString(L"", 6); + + wchar_t c = iter->c_str()[0]; + if (c == '/') + oBuilder.WriteString(L"file://", 7); + else + oBuilder.WriteString(L"file:///", 8); + oBuilder.WriteEncodeXmlString(iter->c_str(), iter->length()); + + oBuilder.WriteString(L"", 7); + } + + return this->Convert(L"" + oBuilder.GetData() + sXmlPart + L"", sPathInternal); +} diff --git a/HtmlFile/HtmlFile.h b/HtmlFile/HtmlFile.h index 3620521211..0e04d2903b 100644 --- a/HtmlFile/HtmlFile.h +++ b/HtmlFile/HtmlFile.h @@ -33,6 +33,16 @@ public: /// \return 1 error, 0 - success /// int Convert(const std::wstring& sXml, const std::wstring& sPathInternal = L""); + + /// + /// \brief ConvertEpub + /// \param sFolder - unzip folder (slash or without slash) + /// \param sMetaInfo - epub meta data + /// \param sXmlPart - file:///D:/activex/AVS/Sources/TeamlabOffice/trunk/OfficeWeb/Word/sdk-all.jsD:/test/Document/ (end /!!!) + /// \param sPathInternal - like Convert html + /// \return 1 error, 0 - success + /// + int ConvertEpub(const std::wstring& sFolder, std::wstring& sMetaInfo, const std::wstring& sXmlPart, const std::wstring& sPathInternal = L""); }; #endif // _HTMLFILE_HTMLFILE_H_ diff --git a/HtmlFile/HtmlFile.pro b/HtmlFile/HtmlFile.pro index 96173eae4f..b8c42039cb 100644 --- a/HtmlFile/HtmlFile.pro +++ b/HtmlFile/HtmlFile.pro @@ -45,7 +45,8 @@ linux-g++:!contains(QMAKE_HOST.arch, x86_64):{ shared { DEFINES += HTMLFILE_USE_DYNAMIC_LIBRARY - LIBS += -L$$DESTDIR -llibxml + LIB_XML_PRI_PATH = ../DesktopEditor/xml + include(../DesktopEditor/xml/build/qt/libxml2.pri) message(dynamic) diff --git a/HtmlFile/test/main.cpp b/HtmlFile/test/main.cpp index e5d3760d19..3d6868d60a 100644 --- a/HtmlFile/test/main.cpp +++ b/HtmlFile/test/main.cpp @@ -3,6 +3,8 @@ int main(int argc, char *argv[]) { +#if 0 + #ifdef WIN32 std::wstring sPath = NSFile::GetProcessDirectory() + L"/../../Internal/windows/Release/"; @@ -29,5 +31,33 @@ int main(int argc, char *argv[]) int nResult = oFile.Convert(sXml, sPath); nResult; +#else + +#ifdef WIN32 + std::wstring sPath = NSFile::GetProcessDirectory() + L"/../../Internal/windows/Release/"; + + std::wstring sXml = L"\ +file:///D:/activex/AVS/Sources/TeamlabOffice/trunk/OfficeWeb/Word/sdk-all.js\ +D:/test/Document/\ +"; +#else + std::wstring sPath = NSFile::GetProcessDirectory() + L"/../../Internal/linux/Release/"; + + std::wstring sXml = L"\ +\ +file:///home/oleg/activex/AVS/Sources/TeamlabOffice/trunk/OfficeWeb/Word/sdk-all.js\ +file:///home/oleg/activex/test.html\ +/home/oleg/activex/1/\ +\ +"; +#endif + + CHtmlFile oFile; + std::wstring sMetaInfo; + int nResult = oFile.ConvertEpub(L"D:\\37898EB", sMetaInfo, sXml, sPath); + nResult; + +#endif + return 0; }