328 lines
14 KiB
C++
328 lines
14 KiB
C++
/*
|
||
* (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<OOX::File> &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<OOX::Spreadsheet::CChartFile> chart_file = file.smart_dynamic_cast<OOX::Spreadsheet::CChartFile>();
|
||
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<OOX::Spreadsheet::CChartExFile> chartEx_file = file.smart_dynamic_cast<OOX::Spreadsheet::CChartExFile>();
|
||
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<OOX::File> &file)
|
||
{
|
||
NSCommon::smart_ptr<OOX::Spreadsheet::CChartFile> oChart = file.smart_dynamic_cast<OOX::Spreadsheet::CChartFile>();
|
||
|
||
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;
|
||
}
|
||
};
|