/* * (c) Copyright Ascensio System SIA 2010-2023 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ #include "XlsxSerializer.h" #include "../../../../DesktopEditor/common/Directory.h" #include "../../../../DesktopEditor/common/File.h" #include "../../../../DesktopEditor/common/Path.h" #include "../../../XlsxFormat/Chart/Chart.h" #include "../../Sheets/Reader/BinaryWriterS.h" #include "../../Sheets/Writer/BinaryReaderS.h" #include "../../Presentation/FontPicker.h" #include "../../../../OfficeUtils/src/OfficeUtils.h" #include "ChartSerializer.h" #include "../BinReader/DefaultThemeWriter.h" namespace BinXlsxRW{ int g_nCurFormatVersion = 0; CXlsxSerializer::CXlsxSerializer() : m_bIsMacro(false), m_bIsNoBase64(false) { m_pExternalDrawingConverter = NULL; } CXlsxSerializer::~CXlsxSerializer() { } void CXlsxSerializer::CreateXlsxFolders(const std::wstring& sXmlOptions, const std::wstring& sDstPath, std::wstring& sMediaPath, std::wstring& sEmbedPath) { OOX::CPath pathMediaDir = sDstPath + FILE_SEPARATOR_STR + _T("xl") + FILE_SEPARATOR_STR + _T("media"); OOX::CPath pathEmbedDir = sDstPath + FILE_SEPARATOR_STR + _T("xl") + FILE_SEPARATOR_STR + _T("embeddings"); //создавать папку надо даже при сохранении в csv, потому что когда читаем из бинарника тему, она записывается в файл. OOX::CPath pathXlDir = sDstPath + FILE_SEPARATOR_STR + _T("xl"); OOX::CPath pathThemeDir = pathXlDir + FILE_SEPARATOR_STR + OOX::FileTypes::Theme.DefaultDirectory().GetPath(); OOX::CPath pathThemeFile = pathThemeDir + FILE_SEPARATOR_STR + OOX::FileTypes::Theme.DefaultFileName().GetPath(); OOX::CPath pathThemeThemeRelsDir = pathThemeDir + FILE_SEPARATOR_STR + _T("_rels"); NSDirectory::CreateDirectory(pathXlDir.GetPath()); NSDirectory::CreateDirectory(pathThemeDir.GetPath()); NSDirectory::CreateDirectory(pathThemeThemeRelsDir.GetPath()); NSDirectory::CreateDirectory(pathMediaDir.GetPath()); NSDirectory::CreateDirectory(pathEmbedDir.GetPath()); //Create Default Theme { Writers::DefaultThemeWriter oDefaultThemeWriter; oDefaultThemeWriter.Write(pathThemeFile.GetPath()); } sMediaPath = pathMediaDir.GetPath(); sEmbedPath = pathEmbedDir.GetPath(); } _UINT32 CXlsxSerializer::loadFromFile(const std::wstring& sSrcFileName, const std::wstring& sDstPath, const std::wstring& sXMLOptions, const std::wstring& sMediaDir, const std::wstring& sEmbedDir) { std::wstring strFileInDir = NSSystemPath::GetDirectoryName(sSrcFileName); NSBinPptxRW::CDrawingConverter oDrawingConverter; oDrawingConverter.SetDstPath(sDstPath + FILE_SEPARATOR_STR + L"xl"); oDrawingConverter.SetSrcPath(strFileInDir, XMLWRITER_DOC_TYPE_XLSX); oDrawingConverter.SetMediaDstPath(sMediaDir); oDrawingConverter.SetEmbedDstPath(sEmbedDir); oDrawingConverter.SetTempPath(m_sTempDir); BinXlsxRW::BinaryFileReader oBinaryFileReader; return oBinaryFileReader.ReadFile(sSrcFileName, sDstPath, &oDrawingConverter, sXMLOptions, m_bIsMacro); } _UINT32 CXlsxSerializer::saveToFile(const std::wstring& sDstFileName, const std::wstring& sSrcPath, const std::wstring& sXMLOptions) { COfficeFontPicker* pFontPicker = new COfficeFontPicker(); pFontPicker->Init(m_sFontDir); NSFonts::IFontManager* pFontManager = pFontPicker->get_FontManager(); DocWrapper::FontProcessor fp; fp.setFontManager(pFontManager); NSFontCutter::CEmbeddedFontsManager* pEmbeddedFontsManager = NULL; if (false == m_sEmbeddedFontsDir.empty()) { NSDirectory::CreateDirectory(m_sEmbeddedFontsDir); pFontPicker->SetEmbeddedFontsDirectory(m_sEmbeddedFontsDir); pEmbeddedFontsManager = pFontPicker->GetNativeCutter(); //добавим мега шрифт pEmbeddedFontsManager->CheckFont(_T("Wingdings 3"), pFontManager); pEmbeddedFontsManager->CheckFont(_T("Arial"), pFontManager); //pEmbeddedFontsManager добавляются все цифры //для заголовков pEmbeddedFontsManager->CheckFont(_T("Calibri"), pFontManager); pEmbeddedFontsManager->CheckString(std::wstring(_T("ABCDEFGHIJKLMNOPQRSTUVWXYZ"))); //дополнение для ошибок "#NULL!", "#DIV/0!"... pEmbeddedFontsManager->CheckString(std::wstring(_T("#!/?"))); //дополнение для num форматов по умолчанию с id от 0 до 49 pEmbeddedFontsManager->CheckString(std::wstring(_T(".%E+-():"))); } NSBinPptxRW::CDrawingConverter oOfficeDrawingConverter; oOfficeDrawingConverter.SetFontManager(pFontManager); oOfficeDrawingConverter.SetFontDir(m_sFontDir); oOfficeDrawingConverter.SetFontPicker(pFontPicker); BinXlsxRW::BinaryFileWriter oBinaryFileWriter(fp); _UINT32 result = oBinaryFileWriter.Open(sSrcPath, sDstFileName, pEmbeddedFontsManager, &oOfficeDrawingConverter, sXMLOptions, m_bIsNoBase64); RELEASEOBJECT(pFontPicker); return result; } _UINT32 CXlsxSerializer::xml2Xlsx(const std::wstring& sSrcFileName, const std::wstring& sDstPath, const std::wstring& sXMLOptions) { std::wstring strFileInDir = NSSystemPath::GetDirectoryName(sSrcFileName); NSBinPptxRW::CDrawingConverter oDrawingConverter; oDrawingConverter.SetDstPath(sDstPath + FILE_SEPARATOR_STR + L"xl"); oDrawingConverter.SetSrcPath(strFileInDir, XMLWRITER_DOC_TYPE_XLSX); oDrawingConverter.SetFontDir(m_sFontDir); BinXlsxRW::BinaryFileReader oBinaryFileReader; return oBinaryFileReader.Xml2Xlsx(sSrcFileName, sDstPath, &oDrawingConverter, sXMLOptions, m_bIsMacro); } bool CXlsxSerializer::saveChart(NSBinPptxRW::CBinaryFileReader* pReader, long lLength, NSCommon::smart_ptr &file) { if (NULL == pReader) return false; if (NULL == m_pExternalDrawingConverter) return false; if (false == file.IsInit()) return false; m_pExternalDrawingConverter->SetDstContentRels(); std::wstring sContentTypePath; if (pReader->m_nDocumentType == XMLWRITER_DOC_TYPE_DOCX || pReader->m_nDocumentType == XMLWRITER_DOC_TYPE_DOCX_GLOSSARY) sContentTypePath = L"/word/charts/"; else if (pReader->m_nDocumentType == XMLWRITER_DOC_TYPE_XLSX) sContentTypePath = L"/xl/charts/"; else sContentTypePath = L"/ppt/charts/"; std::wstring sChartPath = pReader->m_pRels->m_pManager->GetDstCharts(); size_t nIndex = sChartPath.rfind(FILE_SEPARATOR_CHAR); std::wstring sFilePathDocument = sChartPath; if (std::wstring::npos != nIndex) { sFilePathDocument = sFilePathDocument.substr(0, nIndex + 1); } std::wstring sDrawingsPath = sFilePathDocument + L"drawings"; std::wstring sThemePath = sFilePathDocument + L"theme"; std::wstring sEmbedingPath = sFilePathDocument + L"embeddings"; std::wstring sFileName; BinXlsxRW::SaveParams oSaveParams(sDrawingsPath, sEmbedingPath, sThemePath, m_pExternalDrawingConverter->GetContentTypes(), NULL, true); BinXlsxRW::BinaryChartReader oBinaryChartReader(*pReader, oSaveParams, m_pExternalDrawingConverter); bool bResult = false; int nDocumentTypeOwner = pReader->m_pRels->m_pManager->m_nDocumentType; pReader->m_pRels->m_pManager->m_nDocumentType = XMLWRITER_DOC_TYPE_XLSX; NSCommon::smart_ptr chart_file = file.smart_dynamic_cast(); if (chart_file.IsInit()) { sFileName = L"chart" + std::to_wstring(chart_file->GetGlobalNumber()) + L".xml"; bResult = (0 == oBinaryChartReader.ReadCT_ChartFile(lLength, chart_file.GetPointer())); bool bXlsxPresent = (chart_file->m_oChartSpace.m_externalData) && (chart_file->m_oChartSpace.m_externalData->m_id.IsInit()); if (bResult && pReader->m_nDocumentType != XMLWRITER_DOC_TYPE_XLSX && !sEmbedingPath.empty() && !bXlsxPresent) { oSaveParams.bMacroEnabled = false; std::wstring sXlsxFilename = L"Microsoft_Excel_Worksheet" + std::to_wstring(pReader->m_nCountEmbedded) + L".xlsx"; std::wstring sXlsxPath = sEmbedingPath + FILE_SEPARATOR_STR + sXlsxFilename; pReader->m_nCountEmbedded++; if (writeChartXlsx(sXlsxPath, file)) { pReader->m_pRels->m_pManager->m_pContentTypes->AddDefault(L"xlsx"); std::wstring sChartsWorksheetRelsName = L"../embeddings/" + sXlsxFilename; unsigned int rId; std::wstring sChartsWorksheetRelType = OOX::FileTypes::MicrosoftOfficeExcelWorksheet.RelationType(); m_pExternalDrawingConverter->WriteRels(sChartsWorksheetRelType, sChartsWorksheetRelsName, std::wstring(), &rId); chart_file->m_oChartSpace.m_externalData = new OOX::Spreadsheet::CT_ExternalData(); chart_file->m_oChartSpace.m_externalData->m_id = L"rId" + std::to_wstring(rId); chart_file->m_oChartSpace.m_externalData->m_autoUpdate = false; } } } else { NSCommon::smart_ptr chartEx_file = file.smart_dynamic_cast(); if (chartEx_file.IsInit()) { sFileName = L"chartEx" + std::to_wstring(chartEx_file->GetGlobalNumber()) + L".xml"; bResult = (0 == oBinaryChartReader.ReadCT_ChartExFile(lLength, chartEx_file.GetPointer())); bool bXlsxPresent = (chartEx_file->m_oChartSpace.m_chartData.m_externalData.IsInit()) && (chartEx_file->m_oChartSpace.m_chartData.m_externalData->m_id.IsInit()); } } pReader->m_pRels->m_pManager->m_nDocumentType = nDocumentTypeOwner; if(bResult) { if (pReader->m_nDocumentType != XMLWRITER_DOC_TYPE_DOCX && pReader->m_nDocumentType != XMLWRITER_DOC_TYPE_DOCX_GLOSSARY) { file->m_sOutputFilename = L"../"; } file->m_sOutputFilename += L"charts/" + sFileName; std::wstring sFilePath = sChartPath + FILE_SEPARATOR_STR + sFileName; file->write(sFilePath, sContentTypePath, *pReader->m_pRels->m_pManager->m_pContentTypes); OOX::CPath pathRelsDir = sChartPath + FILE_SEPARATOR_STR + _T("_rels"); OOX::CSystemUtility::CreateDirectories(pathRelsDir.GetPath()); OOX::CPath pathRelsFile = pathRelsDir + FILE_SEPARATOR_STR + NSSystemPath::GetFileName(sFilePath) + _T(".rels"); m_pExternalDrawingConverter->SaveDstContentRels(pathRelsFile.GetPath()); } return bResult; } void CXlsxSerializer::setTempDir(const std::wstring& sTempDir) { m_sTempDir = sTempDir; } void CXlsxSerializer::setFontDir(const std::wstring& sFontDir) { m_sFontDir = sFontDir; } void CXlsxSerializer::setEmbeddedFontsDir(const std::wstring& sEmbeddedFontsDir) { m_sEmbeddedFontsDir = sEmbeddedFontsDir; } void CXlsxSerializer::setDrawingConverter(NSBinPptxRW::CDrawingConverter* pDrawingConverter) { m_pExternalDrawingConverter = pDrawingConverter; } void CXlsxSerializer::setIsNoBase64(bool val) { m_bIsNoBase64 = val; } void CXlsxSerializer::setMacroEnabled(bool val) { m_bIsMacro = val; } bool CXlsxSerializer::getMacroEnabled() { return m_bIsMacro; } bool CXlsxSerializer::writeChartXlsx(const std::wstring& sDstFile, NSCommon::smart_ptr &file) { NSCommon::smart_ptr oChart = file.smart_dynamic_cast(); if (oChart.IsInit() == false) return false; //анализируем chart BinXlsxRW::ChartWriter helper; helper.parseChart(oChart->m_oChartSpace.m_chart); //создаем temp std::wstring sTempDir = NSSystemPath::GetDirectoryName(sDstFile) + FILE_SEPARATOR_STR + NSSystemPath::GetFileName(sDstFile) + L"_TEMP"; NSDirectory::CreateDirectory(sTempDir); OOX::CPath oPath(sTempDir.c_str()); //шиблонные папки std::wstring sXmlOptions = _T(""); std::wstring sMediaPath;// will be filled by 'CreateXlsxFolders' method std::wstring sEmbedPath; // will be filled by 'CreateXlsxFolders' method CreateXlsxFolders (sXmlOptions, sTempDir, sMediaPath, sEmbedPath); //заполняем Xlsx OOX::Spreadsheet::CXlsx oXlsx; helper.toXlsx(oXlsx); //write OOX::CContentTypes oContentTypes; bool res = oXlsx.Write(oPath, oContentTypes); if (res) { //zip COfficeUtils oOfficeUtils(NULL); oOfficeUtils.CompressFileOrDirectory(sTempDir, sDstFile, true); } //clean NSDirectory::DeleteDirectory(sTempDir); return res; } };