Files
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

504 lines
18 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 "Xlsb.h"
#include "../DocxFormat/App.h"
#include "../DocxFormat/Core.h"
#include "../XlsxFormat/Workbook/Workbook.h"
#include "../XlsxFormat/SharedStrings/SharedStrings.h"
#include "../XlsxFormat/Styles/Styles.h"
#include "../XlsxFormat/Worksheets/Worksheet.h"
#include "../XlsxFormat/CalcChain/CalcChain.h"
#include "../XlsxFormat/ExternalLinks/ExternalLinks.h"
#include "../XlsxFormat/ExternalLinks/ExternalLinkPath.h"
#include "../XlsxFormat/Pivot/PivotTable.h"
#include "../XlsxFormat/Pivot/PivotCacheDefinition.h"
#include "../XlsxFormat/Pivot/PivotCacheRecords.h"
#include "../XlsxFormat/Styles/Fonts.h"
#include "../../MsBinaryFile/XlsFile/Format/Logic/GlobalWorkbookInfo.h"
#include "../../MsBinaryFile/XlsFile/Format/Logic/WorkbookStreamObject.h"
#include "../../MsBinaryFile/XlsFile/Format/Binary/CFStreamCacheReader.h"
#include "../../MsBinaryFile/XlsFile/Format/Binary/CFStreamCacheWriter.h"
#include "../../MsBinaryFile/XlsFile/Format/Logic/BinProcessor.h"
#include "../Binary/Presentation/BinaryFileReaderWriter.h"
#include "../../DesktopEditor/common/SystemUtils.h"
#include "Biff12_unions/CELLTABLE.h"
using namespace XLS;
OOX::Spreadsheet::CXlsb::~CXlsb()
{
}
void OOX::Spreadsheet::CXlsb::init()
{
workbook_code_page = XLS::WorkbookStreamObject::DefaultCodePage;
xls_global_info = boost::shared_ptr<XLS::GlobalWorkbookInfo>(new XLS::GlobalWorkbookInfo(workbook_code_page, nullptr));
xls_global_info->Version = 0x0800;
m_binaryReader = boost::shared_ptr<NSBinPptxRW::CBinaryFileReader>(new NSBinPptxRW::CBinaryFileReader);
m_binaryWriter = boost::shared_ptr<NSBinPptxRW::CXlsbBinaryWriter>(new NSBinPptxRW::CXlsbBinaryWriter);
m_bWriteToXlsx = false;
}
bool OOX::Spreadsheet::CXlsb::ReadBin(const CPath& oFilePath, XLS::BaseObject* objStream)
{
NSFile::CFileBinary oFile;
if (oFile.OpenFile(oFilePath.GetPath()) == false)
return false;
auto m_lStreamLen = (LONG)oFile.GetFileSize();
auto m_pStream = new BYTE[m_lStreamLen];
DWORD dwRead = 0;
oFile.ReadFile(m_pStream, (DWORD)m_lStreamLen, dwRead);
oFile.CloseFile();
m_binaryReader->Init(m_pStream, 0, dwRead);
XLS::StreamCacheReaderPtr reader(new XLS::BinaryStreamCacheReader(m_binaryReader, xls_global_info));
XLS::BinReaderProcessor proc(reader, objStream, true);
proc.mandatory(*objStream);
delete[] m_pStream;
//reader.reset();
return true;
}
XLS::StreamCacheReaderPtr OOX::Spreadsheet::CXlsb::GetFileReader(const CPath& oFilePath, BYTE* &streamBuf)
{
NSFile::CFileBinary oFile;
if (oFile.OpenFile(oFilePath.GetPath()) == false)
return nullptr;
auto m_lStreamLen = (LONG)oFile.GetFileSize();
streamBuf = new BYTE[m_lStreamLen];
DWORD dwRead = 0;
oFile.ReadFile(streamBuf, (DWORD)m_lStreamLen, dwRead);
oFile.CloseFile();
m_binaryReader->Init(streamBuf, 0, dwRead);
XLS::StreamCacheReaderPtr reader(new XLS::BinaryStreamCacheReader(m_binaryReader, xls_global_info));
return reader;
}
XLS::StreamCacheWriterPtr OOX::Spreadsheet::CXlsb::GetFileWriter(const CPath& oFilePath)
{
if (m_binaryWriter->CreateFileW(oFilePath.GetPath()) == false)
return nullptr;
XLS::StreamCacheWriterPtr writer(new XLS::BinaryStreamCacheWriter(m_binaryWriter, xls_global_info));
return writer;
}
bool OOX::Spreadsheet::CXlsb::WriteSreamCache(XLS::StreamCacheWriterPtr writer)
{
auto writeSucced = m_binaryWriter->WriteFile(m_binaryWriter->GetBuffer(), (static_cast<NSBinPptxRW::CBinaryFileWriter*>(m_binaryWriter.get()))->GetPosition());
if(writeSucced)
(static_cast<NSBinPptxRW::CBinaryFileWriter*>(m_binaryWriter.get()))->SetPosition(0);
m_binaryWriter->CloseFile();
return writeSucced;
}
bool OOX::Spreadsheet::CXlsb::WriteBin(const CPath& oDirPath, OOX::CContentTypes& oContentTypes)
{
if (NULL == m_pWorkbook)
return false;
m_bWriteToXlsb = true;
if(!m_oContentTypes.m_mapDefaults.empty() && !m_oContentTypes.m_mapOverrides.empty())
{
oContentTypes.Merge(&m_oContentTypes);
}
IFileContainer::Write(oDirPath / L"", OOX::CPath(_T("")), oContentTypes);
oContentTypes.Write(oDirPath);
return true;
}
bool OOX::Spreadsheet::CXlsb::WriteBin(const CPath& oFilePath, XLS::BaseObject* objStream)
{
if (m_binaryWriter->CreateFileW(oFilePath.GetPath()) == false)
return false;
XLS::StreamCacheWriterPtr writer(new XLS::BinaryStreamCacheWriter(m_binaryWriter, xls_global_info));
XLS::BinWriterProcessor proc(writer, objStream);
proc.mandatory(*objStream);
auto writeSucced = m_binaryWriter->WriteFile(m_binaryWriter->GetBuffer(), (static_cast<NSBinPptxRW::CBinaryFileWriter*>(m_binaryWriter.get()))->GetPosition());
if(writeSucced)
(static_cast<NSBinPptxRW::CBinaryFileWriter*>(m_binaryWriter.get()))->SetPosition(0);
m_binaryWriter->CloseFile();
return true;
}
void OOX::Spreadsheet::CXlsb::WriteSheetData()
{
for(auto &worksheet : m_arWorksheets)
{
//для оптимизации по памяти сразу записываем в файл все листы
if(m_bWriteToXlsb)
{
WriteSheet(worksheet);
}//
//cell_table_temlate.reset();
//reader.reset();
}
}
XLS::GlobalWorkbookInfo* OOX::Spreadsheet::CXlsb::GetGlobalinfo()
{
return xls_global_info.get();
}
void OOX::Spreadsheet::CXlsb::PrepareSi()
{
if(m_pStyles && m_pStyles->m_oFonts.IsInit())
{
auto lambdaSi = [&](OOX::Spreadsheet::CSi* si) {
for(size_t i = 0, length = si->m_arrItems.size(); i < length; ++i)
{
OOX::Spreadsheet::WritingElement* we = si->m_arrItems[i];
if(OOX::et_x_r == we->getType())
{
OOX::Spreadsheet::CRun* pRun = static_cast<OOX::Spreadsheet::CRun*>(we);
if(pRun->m_oRPr.IsInit() && pRun->m_oRPr->m_nFontIndex.IsInit())
{
CFont* font = nullptr;
auto findFont = m_pStyles->m_oFonts->m_mapFonts.find(pRun->m_oRPr->m_nFontIndex->GetValue());
if(findFont != m_pStyles->m_oFonts->m_mapFonts.end())
font = findFont->second;
if(font != nullptr)
pRun->m_oRPr->fromFont(font);
}
}
}
};
if(m_pSharedStrings)
{
for(auto &si : m_pSharedStrings->m_arrItems)
{
lambdaSi(si);
}
}
/*if(!m_arWorksheets.empty())
{
for(auto &wsheet : m_arWorksheets)
{
for(auto &comment : wsheet->m_mapComments)
{
auto si = comment.second->m_oText;
lambdaSi(si.GetPointer());
}
}
}*/
}
}
//подготовка шрифтов в richString для конвертации в xlsb
void OOX::Spreadsheet::CXlsb::PrepareRichStr()
{
if(m_pStyles && m_pStyles->m_oFonts.IsInit())
{
auto lambdaSi = [&](OOX::Spreadsheet::CSi* si)
{
for(size_t i = 0, length = si->m_arrItems.size(); i < length; ++i)
{
OOX::Spreadsheet::WritingElement* we = si->m_arrItems[i];
if(OOX::et_x_r == we->getType())
{
OOX::Spreadsheet::CRun* pRun = static_cast<OOX::Spreadsheet::CRun*>(we);
if(pRun->m_oRPr.IsInit() && !pRun->m_oRPr->m_nFontIndex.IsInit())
{
auto font = pRun->m_oRPr->toFont();
m_pStyles->m_oFonts->AddFont(font);
pRun->m_oRPr->m_nFontIndex.Init();
pRun->m_oRPr->m_nFontIndex = m_pStyles->m_oFonts->m_arrItems.size() - 1;
}
}
}
};
if(m_pSharedStrings)
{
for(auto &si : m_pSharedStrings->m_arrItems)
{
lambdaSi(si);
}
}
}
}
//отложенный парсинг SheetData
void OOX::Spreadsheet::CXlsb::ReadSheetData()
{
for(auto &worksheet : m_arWorksheets)
{
_UINT32 dataPosition;
auto dataFindPair = m_mapSheetNameSheetData.find(worksheet->GetReadPath().GetPath());
if(dataFindPair != m_mapSheetNameSheetData.end())
dataPosition = dataFindPair->second;
else
continue;
NSFile::CFileBinary oFile;
if (oFile.OpenFile(worksheet->GetReadPath().GetPath()) == false)
continue;
auto m_lStreamLen = (LONG)oFile.GetFileSize();
if(dataPosition > m_lStreamLen)
continue;
auto m_pStream = new BYTE[m_lStreamLen];
DWORD dwRead = 0;
oFile.ReadFile(m_pStream, (DWORD)m_lStreamLen, dwRead);
oFile.CloseFile();
m_binaryReader->Init(m_pStream, 0, dwRead);
XLS::BaseObjectPtr cell_table_temlate = XLS::BaseObjectPtr(new XLSB::CELLTABLE());
XLS::StreamCacheReaderPtr reader(new XLS::BinaryStreamCacheReader(m_binaryReader, xls_global_info));
//XLS::BinReaderProcessor proc(reader, cell_table_temlate.get(), true);
reader->SetRecordPosition(dataPosition);
//proc.mandatory(*cell_table_temlate.get());
//auto base = boost::static_pointer_cast<BaseObject>(cell_table_temlate);
worksheet->m_oSheetData->fromBin(reader);
delete[] m_pStream;
//для оптимизации по памяти сразу записываем в файл все листы
if(m_bWriteToXlsx)
{
WriteSheet(worksheet);
}
//cell_table_temlate.reset();
//reader.reset();
}
}
void OOX::Spreadsheet::CXlsb::SetPropForWriteSheet(const std::wstring &sPath, OOX::CContentTypes& oContentTypes)
{
m_sPath = sPath + L"/xl";
m_oContentTypes = oContentTypes;
}
bool OOX::Spreadsheet::CXlsb::IsWriteToXlsx()
{
return m_bWriteToXlsx;
}
void OOX::Spreadsheet::CXlsb::WriteToXlsx(bool isXlsx)
{
m_bWriteToXlsx = isXlsx;
}
void OOX::Spreadsheet::CXlsb::WriteSheet(CWorksheet* worksheet)
{
OOX::CPath oDefDir = worksheet->DefaultDirectory();
OOX::CPath oName = worksheet->DefaultFileName();
if (false == worksheet->m_sOutputFilename.empty())
oName.SetName(worksheet->m_sOutputFilename, false);
OOX::CSystemUtility::CreateDirectories(m_sPath);
OOX::CSystemUtility::CreateDirectories( m_sPath / oDefDir );
worksheet->write( m_sPath / oDefDir / oName, L"/xl/" + oDefDir, m_oContentTypes );
worksheet->m_oSheetData.reset();
}
void OOX::Spreadsheet::CXlsb::PrepareTableFormula()
{
auto lambdaFormula = [&](std::wstring& formula) {
auto str = STR::guidFromStr(formula);
while(!str.empty())
{
auto guidTableIndex = this->xls_global_info->mapTableGuidsIndex.find(str);
if (guidTableIndex != this->xls_global_info->mapTableGuidsIndex.end())
{
auto tableIndex = this->xls_global_info->mapTableNames.find(guidTableIndex->second);
if (tableIndex != this->xls_global_info->mapTableNames.end())
{
auto tableName = tableIndex->second;
formula.replace(formula.find(str), str.size(), tableName);
}
else
{
formula.replace(formula.find(str), str.size(), L"#NAME?");
}
}
else
break;
str = STR::guidFromStr(formula);
}
};
for(auto &worksheet : m_arWorksheets)
{
if(worksheet->m_oTableParts.IsInit())
{
for(size_t i = 0, length = worksheet->m_oTableParts->m_arrItems.size(); i < length; ++i)
{
auto &oTablePart = worksheet->m_oTableParts->m_arrItems[i];
if(oTablePart->m_oRId.IsInit())
{
smart_ptr<OOX::File> pFile = worksheet->Find(OOX::RId(oTablePart->m_oRId->GetValue()));
if (pFile.IsInit() && OOX::Spreadsheet::FileTypes::Table == pFile->type())
{
OOX::Spreadsheet::CTableFile* pTableFile = static_cast<OOX::Spreadsheet::CTableFile*>(pFile.GetPointer());
if(pTableFile && pTableFile->m_oTable.IsInit())
{
OOX::Spreadsheet::CTable* pTable = pTableFile->m_oTable.GetPointer();
if(pTable->m_oTableColumns.IsInit())
{
OOX::Spreadsheet::CTableColumns* oTableColumns = pTable->m_oTableColumns.GetPointer();
for(size_t i = 0, length = oTableColumns->m_arrItems.size(); i < length; ++i)
{
auto& oTableColumn = oTableColumns->m_arrItems[i];
if(oTableColumn->m_oCalculatedColumnFormula.IsInit())
{
lambdaFormula(oTableColumn->m_oCalculatedColumnFormula.get());
}
if(oTableColumn->m_oTotalsRowFormula.IsInit())
{
lambdaFormula(oTableColumn->m_oTotalsRowFormula.get());
}
}
}
}
}
}
}
/*if(worksheet->m_oSheetData.IsInit())
{
for(size_t i = 0, length = worksheet->m_oSheetData->m_arrItems.size(); i < length; ++i)
{
OOX::Spreadsheet::CRow* pRow = worksheet->m_oSheetData->m_arrItems[i];
if(pRow)
{
for(size_t i = 0, length = pRow->m_arrItems.size(); i < length; ++i)
{
OOX::Spreadsheet::CCell* oCell = pRow->m_arrItems[i];
if(oCell->m_oFormula.IsInit())
{
lambdaFormula(oCell->m_oFormula.GetPointer()->m_sText);
}
}
}
}
}*/
}
}
if(m_pWorkbook && m_pWorkbook->m_oDefinedNames.IsInit())
{
for(auto defName:m_pWorkbook->m_oDefinedNames->m_arrItems)
{
if(defName->m_oRef.IsInit())
{
lambdaFormula(defName->m_oRef.get());
}
}
}
}
void OOX::Spreadsheet::CXlsb::LinkTables()
{
{
bool tablesExist = false;
for(auto worksheet:m_arWorksheets)
{
if(worksheet->m_oTableParts.IsInit())
tablesExist = true;
}
if(!tablesExist)
return;
}
for(auto xti:XLS::GlobalWorkbookInfo::arXti_External_static)
{
if(xti.itabFirst != xti.itabLast)
{
continue;
}
auto sheetName = xti.link;
if(!m_pWorkbook || !m_pWorkbook->m_oSheets.IsInit())
continue;
OOX::Spreadsheet::CSheet * bundle;
for(auto i:m_pWorkbook->m_oSheets->m_arrItems)
{
if(i->m_oName.IsInit() && i->m_oName.get() == sheetName)
{
bundle = i;
}
}
if(!bundle || !bundle->m_oRid.IsInit())
continue;
auto FilePtr = m_pWorkbook->Find(bundle->m_oRid->GetValue());
if(!FilePtr.IsInit() || !(OOX::Spreadsheet::FileTypes::Worksheet == FilePtr->type()))
continue;
auto WorksheetFile = static_cast<OOX::Spreadsheet::CWorksheet*>(FilePtr.GetPointer());
if(!WorksheetFile->m_oTableParts.IsInit())
continue;
for(auto tablePart : WorksheetFile->m_oTableParts->m_arrItems)
{
if(tablePart->m_oRId.IsInit())
{
auto tableFilePtr = WorksheetFile->Find(tablePart->m_oRId->GetValue());
if(tableFilePtr.IsInit() && OOX::Spreadsheet::FileTypes::Table == tableFilePtr->type())
{
auto tableFile = static_cast<OOX::Spreadsheet::CTableFile*>(tableFilePtr.GetPointer());
if(tableFile->m_oTable.IsInit() && tableFile->m_oTable->m_oId.IsInit())
{
if(!XLS::GlobalWorkbookInfo::mapXtiTables_static.count(xti.itabFirst))
{
XLS::GlobalWorkbookInfo::mapXtiTables_static.emplace(xti.itabFirst, std::vector<int>());
}
XLS::GlobalWorkbookInfo::mapXtiTables_static.at(xti.itabFirst).push_back(tableFile->m_oTable->m_oId->GetValue());
}
}
}
}
}
}