diff --git a/OOXML/Binary/Sheets/Reader/CSVReader.cpp b/OOXML/Binary/Sheets/Reader/CSVReader.cpp index b5ba3a8e5b..ca279d0a58 100644 --- a/OOXML/Binary/Sheets/Reader/CSVReader.cpp +++ b/OOXML/Binary/Sheets/Reader/CSVReader.cpp @@ -30,7 +30,7 @@ * */ #include "CSVReader.h" -#include "CellFormatController.h" +#include "CellFormatController/CellFormatController.h" #include "../../../XlsbFormat/Xlsb.h" #include "../../../XlsxFormat/Worksheets/Worksheet.h" diff --git a/OOXML/Binary/Sheets/Reader/CellFormatController.cpp b/OOXML/Binary/Sheets/Reader/CellFormatController/CellFormatController.cpp similarity index 53% rename from OOXML/Binary/Sheets/Reader/CellFormatController.cpp rename to OOXML/Binary/Sheets/Reader/CellFormatController/CellFormatController.cpp index bc90be547c..59fe3ad8b4 100644 --- a/OOXML/Binary/Sheets/Reader/CellFormatController.cpp +++ b/OOXML/Binary/Sheets/Reader/CellFormatController/CellFormatController.cpp @@ -31,9 +31,16 @@ */ #include "CellFormatController.h" +#include "DateReader.h" -#include "../../../XlsxFormat/Styles/NumFmts.h" -#include "../../../XlsxFormat/Styles/Xfs.h" +#include "../../../../XlsxFormat/Styles/NumFmts.h" +#include "../../../../XlsxFormat/Styles/Xfs.h" + +#include +#include +#include + +const std::wstring DefaultDateFormat = L"DD.MM.YYYY"; CellFormatController::CellFormatController(OOX::Spreadsheet::CStyles *styles): m_pStyles{styles} @@ -64,108 +71,75 @@ CellFormatController::CellFormatController(OOX::Spreadsheet::CStyles *styles): pXfs->m_oAligment.Init(); pXfs->m_oAligment->m_oWrapText.Init(); pXfs->m_oAligment->m_oWrapText->SetValue(SimpleTypes::onoffTrue); + m_pStyles->m_oCellXfs->m_arrItems.push_back(pXfs); + + m_pStyles->m_oNumFmts.Init(); + m_pStyles->m_oNumFmts->m_arrItems.push_back(new OOX::Spreadsheet::CNumFmt()); + m_pStyles->m_oNumFmts->m_arrItems.back()->m_oFormatCode = DefaultDateFormat; + m_pStyles->m_oNumFmts->m_arrItems.back()->m_oNumFmtId.Init(); + m_pStyles->m_oNumFmts->m_arrItems.back()->m_oNumFmtId->SetValue(164 + m_pStyles->m_oNumFmts->m_arrItems.size()); + + // Normal + data format + pXfs = new OOX::Spreadsheet::CXfs(); + + pXfs->m_oBorderId.Init(); pXfs->m_oBorderId->SetValue(0); + pXfs->m_oFillId.Init(); pXfs->m_oFillId->SetValue(0); + pXfs->m_oFontId.Init(); pXfs->m_oFontId->SetValue(0); + pXfs->m_oNumFmtId.Init(); pXfs->m_oNumFmtId->SetValue(m_pStyles->m_oNumFmts->m_arrItems.back()->m_oNumFmtId->GetValue()); + + m_pStyles->m_oCellXfs->m_arrItems.push_back(pXfs); + auto styleId = (unsigned int)(m_pStyles->m_oCellXfs->m_arrItems.size() - 1); + mapDataNumber.insert(std::make_pair(DefaultDateFormat, styleId)); + } void CellFormatController::ProcessCellType(OOX::Spreadsheet::CCell *pCell, const std::wstring &value, bool bIsWrap) { + + pCell_ = pCell; + /// формат для булева значения в верхнем регистре + if(value == L"true" || value == L"false") + { + pCell->m_oType->SetValue(SimpleTypes::Spreadsheet::celltypeInlineStr); + pCell->m_oRichText.Init(); + OOX::Spreadsheet::CText *pText = new OOX::Spreadsheet::CText(); + auto tempValue = value; + std::transform(tempValue.begin(), tempValue.end(), tempValue.begin(), + [](unsigned char c) { return std::toupper(c); }); + pText->m_sText = tempValue; + pCell->m_oRichText->m_arrItems.push_back(pText); + return; + } + size_t length = value.length(); wchar_t *pEndPtr; double dValue = wcstod(value.c_str(), &pEndPtr); + value_ = &value; if (std::isnan(dValue) || std::isinf(dValue)) pEndPtr = (wchar_t *)value.c_str(); if ((0 == *pEndPtr) || (pEndPtr != value.c_str() && (value.c_str() + length - pEndPtr) < 3)) { - std::wstring data_format; - std::wstring postfix; - - if (0 != *pEndPtr) + processNumberValue(dValue, pEndPtr); + if (bIsWrap) { - size_t sz = length - (pEndPtr - value.c_str()); - - while (sz > 0) - { - if (pEndPtr[sz - 1] != L' ') - break; - sz--; - } - - if (sz > 0) - { - postfix = std::wstring(pEndPtr, sz); - } + pCell->m_oStyle = 1; } - - size_t pos = value.find(L"."); - if (pos != std::wstring::npos) - { - size_t fraction = value.length() - pos - ((0 != *pEndPtr) ? 2 : 1); - for (size_t i = 0; i < fraction && fraction != std::wstring::npos; ++i) - data_format += L"0"; - } - if (false == data_format.empty()) data_format = L"." + data_format; - - pCell->m_oValue.Init(); - - if (0 != *pEndPtr) - { - if (false == postfix.empty()) - { - if (postfix[0] == L'%') - { - pCell->m_oValue->m_sText = std::to_wstring(dValue / 100.); - } - else - { - pCell->m_oValue->m_sText = value.substr(0, length - 1); - - for (size_t i = 0; i < postfix.size(); ++i) - { - data_format += std::wstring(L"\\") + postfix[i]; - } - } - } - } - else - { - pCell->m_oValue->m_sText = value; - } - if (false == data_format.empty()) - { - data_format = L"0" + data_format; - - std::map::iterator pFind = mapDataNumber.find(data_format); - if (pFind != mapDataNumber.end()) - { - pCell->m_oStyle = pFind->second; - } - else - { - if (!m_pStyles->m_oNumFmts.IsInit()) m_pStyles->m_oNumFmts.Init(); - - m_pStyles->m_oNumFmts->m_arrItems.push_back(new OOX::Spreadsheet::CNumFmt()); - m_pStyles->m_oNumFmts->m_arrItems.back()->m_oFormatCode = data_format; - m_pStyles->m_oNumFmts->m_arrItems.back()->m_oNumFmtId.Init(); - m_pStyles->m_oNumFmts->m_arrItems.back()->m_oNumFmtId->SetValue(164 + m_pStyles->m_oNumFmts->m_arrItems.size()); - - // Normal + data format - OOX::Spreadsheet::CXfs* pXfs = new OOX::Spreadsheet::CXfs(); - - pXfs->m_oBorderId.Init(); pXfs->m_oBorderId->SetValue(0); - pXfs->m_oFillId.Init(); pXfs->m_oFillId->SetValue(0); - pXfs->m_oFontId.Init(); pXfs->m_oFontId->SetValue(0); - pXfs->m_oNumFmtId.Init(); pXfs->m_oNumFmtId->SetValue(m_pStyles->m_oNumFmts->m_arrItems.back()->m_oNumFmtId->GetValue()); - - m_pStyles->m_oCellXfs->m_arrItems.push_back(pXfs); - - pCell->m_oStyle = (unsigned int)(m_pStyles->m_oCellXfs->m_arrItems.size() - 1); - mapDataNumber.insert(std::make_pair(data_format, *pCell->m_oStyle)); - } - } - + return; } + + DateReader dateReader = {}; + auto digitalDate = dateReader.GetDigitalDate(value); + if(digitalDate != 0) + { + pCell->m_oType->SetValue(SimpleTypes::Spreadsheet::ECellTypeType::celltypeDate); + pCell->m_oValue.Init(); + pCell->m_oValue->m_sText = std::to_wstring(digitalDate); + std::map::iterator pFind = mapDataNumber.find(DefaultDateFormat); + pCell_->m_oStyle = pFind->second; + } else { if (value[0] == L'='/* && bCalcFormulas*/) @@ -187,4 +161,146 @@ void CellFormatController::ProcessCellType(OOX::Spreadsheet::CCell *pCell, const { pCell->m_oStyle = 1; } -} \ No newline at end of file + +} + +void CellFormatController::processNumberValue(double dValue, wchar_t *pEndPtr) +{ + std::wstring data_format; + std::wstring postfix; + auto length = value_->length(); + + if (0 != *pEndPtr) + { + size_t sz = length - (pEndPtr - value_->c_str()); + + while (sz > 0) + { + if (pEndPtr[sz - 1] != L' ') + break; + sz--; + } + + if (sz > 0) + { + postfix = std::wstring(pEndPtr, sz); + } + } + + size_t pos = value_->find(L"."); + if (pos != std::wstring::npos) + { + size_t fraction = length - pos - ((0 != *pEndPtr) ? 2 : 1); + for (size_t i = 0; i < fraction && fraction != std::wstring::npos; ++i) + data_format += L"0"; + } + if (false == data_format.empty()) data_format = L"." + data_format; + + pCell_->m_oValue.Init(); + + if (0 != *pEndPtr) + { + if (false == postfix.empty()) + { + if (postfix[0] == L'%') + { + pCell_->m_oValue->m_sText = std::to_wstring(dValue / 100.); + } + else + { + pCell_->m_oValue->m_sText = value_->substr(0, length - 1); + + for (size_t i = 0; i < postfix.size(); ++i) + { + data_format += std::wstring(L"\\") + postfix[i]; + } + } + } + } + else + { + pCell_->m_oValue->m_sText = *value_; + } + if (false == data_format.empty()) + { + data_format = L"0" + data_format; + + std::map::iterator pFind = mapDataNumber.find(data_format); + if (pFind != mapDataNumber.end()) + { + pCell_->m_oStyle = pFind->second; + } + else + { + if (!m_pStyles->m_oNumFmts.IsInit()) m_pStyles->m_oNumFmts.Init(); + m_pStyles->m_oNumFmts->m_arrItems.push_back(new OOX::Spreadsheet::CNumFmt()); + m_pStyles->m_oNumFmts->m_arrItems.back()->m_oFormatCode = data_format; + m_pStyles->m_oNumFmts->m_arrItems.back()->m_oNumFmtId.Init(); + m_pStyles->m_oNumFmts->m_arrItems.back()->m_oNumFmtId->SetValue(164 + m_pStyles->m_oNumFmts->m_arrItems.size()); + + // Normal + data format + OOX::Spreadsheet::CXfs* pXfs = new OOX::Spreadsheet::CXfs(); + + pXfs->m_oBorderId.Init(); pXfs->m_oBorderId->SetValue(0); + pXfs->m_oFillId.Init(); pXfs->m_oFillId->SetValue(0); + pXfs->m_oFontId.Init(); pXfs->m_oFontId->SetValue(0); + pXfs->m_oNumFmtId.Init(); pXfs->m_oNumFmtId->SetValue(m_pStyles->m_oNumFmts->m_arrItems.back()->m_oNumFmtId->GetValue()); + + m_pStyles->m_oCellXfs->m_arrItems.push_back(pXfs); + + pCell_->m_oStyle = (unsigned int)(m_pStyles->m_oCellXfs->m_arrItems.size() - 1); + mapDataNumber.insert(std::make_pair(data_format, *pCell_->m_oStyle)); + } + } +} + +SimpleTypes::Spreadsheet::ECellTypeType CellFormatController::getCellType(const std::wstring &Cellvalue) +{ + if(Cellvalue == L"true" || Cellvalue == L"false") + { + return SimpleTypes::Spreadsheet::ECellTypeType::celltypeBool; + } + wchar_t *pEndPtr; + double dValue = wcstod(Cellvalue.c_str(), &pEndPtr); + + if (std::isnan(dValue) || std::isinf(dValue)) + pEndPtr = (wchar_t *)Cellvalue.c_str(); + + if ((0 == *pEndPtr) || (pEndPtr != Cellvalue.c_str() && (Cellvalue.c_str() + Cellvalue.length() - pEndPtr) < 3)) + { + return SimpleTypes::Spreadsheet::ECellTypeType::celltypeNumber; + } + + if(isValidDate(Cellvalue)) + { + return SimpleTypes::Spreadsheet::ECellTypeType::celltypeDate; + } + + return SimpleTypes::Spreadsheet::ECellTypeType::celltypeInlineStr; +} + +bool CellFormatController::isValidDate(const std::wstring &Cellvalue) +{ + std::wregex format1(L"(0[1-9]|[1-2][0-9]|3[0-1])\\.(0[1-9]|1[0-2])\\.[0-9]{4}"); + std::wregex format2(L"[0-9]{4}\\.(0[1-9]|1[0-2])\\.(0[1-9]|[1-2][0-9]|3[0-1])"); + std::wregex format3(L"(0[1-9]|1[0-2])\\.(0[1-9]|[1-2][0-9]|3[0-1])\\.[0-9]{4}"); + + std::wregex format4(L"(0[1-9]|[1-2][0-9]|3[0-1])\\-(0[1-9]|1[0-2])\\-[0-9]{4}"); + std::wregex format5(L"[0-9]{4}\\-(0[1-9]|1[0-2])\\-(0[1-9]|[1-2][0-9]|3[0-1])"); + std::wregex format6(L"(0[1-9]|1[0-2])\\-(0[1-9]|[1-2][0-9]|3[0-1])\\-[0-9]{4}"); + + std::wregex format7(L"(0[1-9]|[1-2][0-9]|3[0-1])\\/(0[1-9]|1[0-2])\\/[0-9]{4}"); + std::wregex format8(L"[0-9]{4}\\/(0[1-9]|1[0-2])\\/(0[1-9]|[1-2][0-9]|3[0-1])"); + std::wregex format9(L"(0[1-9]|1[0-2])\\/(0[1-9]|[1-2][0-9]|3[0-1])\\/[0-9]{4}"); + + std::vector formatList{format1, format2, format3, format4, format5, format6, + format7, format8, format9}; + for(auto i:formatList) + { + if(std::regex_match(Cellvalue, i)) + { + return true; + } + } + return false; +} diff --git a/OOXML/Binary/Sheets/Reader/CellFormatController.h b/OOXML/Binary/Sheets/Reader/CellFormatController/CellFormatController.h similarity index 62% rename from OOXML/Binary/Sheets/Reader/CellFormatController.h rename to OOXML/Binary/Sheets/Reader/CellFormatController/CellFormatController.h index 2c6c1f123c..d40d74aaa1 100644 --- a/OOXML/Binary/Sheets/Reader/CellFormatController.h +++ b/OOXML/Binary/Sheets/Reader/CellFormatController/CellFormatController.h @@ -32,9 +32,9 @@ #pragma once -#include "../../../Base/Base.h" -#include "../../../XlsxFormat/Worksheets/Worksheet.h" -#include "../../../XlsxFormat/Styles/Styles.h" +#include "../../../../Base/Base.h" +#include "../../../../XlsxFormat/Worksheets/Worksheet.h" +#include "../../../../XlsxFormat/Styles/Styles.h" /// @brief класс определяющий и корректирующий тип данных, помещаемых в ячейки таблицы @@ -53,14 +53,32 @@ public: private: - void processDigitalType(); + /// @brief обработка значения ячейки числового типа + /// @param dValue значение в числовом виде + /// @param EndPtr указатель на конец числа + void processNumberValue(double dValue, wchar_t *pEndPtr); - std::wstring *value; - OOX::Spreadsheet::CCell *pCell; + /// @brief определение типа ячейки по её значению + /// @param Cellvalue текст ячейки + /// @return тип содержимого ячейки + SimpleTypes::Spreadsheet::ECellTypeType getCellType(const std::wstring &Cellvalue); + /// @brief определение того, является ли содержимое ячейки валидным какому-либо формату даты + /// @param Cellvalue текст ячейки + /// @return true если содержимое может быть преобразовано в дату иначе false + bool isValidDate(const std::wstring &Cellvalue); + + /// @brief указатель на ячейку с которой ведется работа + OOX::Spreadsheet::CCell *pCell_; + + /// @brief map с форматами данных std::map mapDataNumber; + /// @brief указатель на стили документа OOX::Spreadsheet::CStyles *m_pStyles; + /// @brief указатель на полученное строковое значение + const std::wstring *value_; + }; diff --git a/OOXML/Binary/Sheets/Reader/CellFormatController/DateReader.cpp b/OOXML/Binary/Sheets/Reader/CellFormatController/DateReader.cpp new file mode 100644 index 0000000000..52b5beff41 --- /dev/null +++ b/OOXML/Binary/Sheets/Reader/CellFormatController/DateReader.cpp @@ -0,0 +1,76 @@ +/* + * (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 "DateReader.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + // Определение основных форматов даты +std::vector DateFormats = { + L"%d.%m.%Y", L"%d.%m.%y", L"%Y-%m-%d", L"%m/%d/%Y", + L"%m/%d/%y", L"%d %B %Y", L"%d %B, %Y", L"%d %b %Y", + L"%d %b, %Y", L"%B %d %Y", L"%B %d, %Y", L"%b %d %Y", + L"%b %d, %Y", L"%Y/%m/%d", L"%Y/%d/%m", L"%m-%d-%Y", + L"%m-%d-%y", L"%d-%m-%Y", L"%d-%m-%y" +}; + +_UINT32 DateReader::GetDigitalDate(const std::wstring &date) +{ + // Перебор форматов даты, пока не найдется подходящий + for (const auto& format : DateFormats) { + std::wistringstream ss(date); + ss.imbue(std::locale("")); // Установка локали по умолчанию + + tm time = {}; + ss >> std::get_time(&time, format.c_str()); + + if (ss.fail()) { + continue; + } + + // Преобразование даты в формат excel + auto tp = std::chrono::system_clock::from_time_t(mktime(&time)); + auto excelTime = (tp.time_since_epoch().count() / 10000000) + 2209161600; + double tempTime = excelTime / 86400.0; + return round(excelTime / 86400.0); + } + + // Если не найден подходящий формат даты, возвращаем 0 + return 0; +} diff --git a/OOXML/Binary/Sheets/Reader/CellFormatController/DateReader.h b/OOXML/Binary/Sheets/Reader/CellFormatController/DateReader.h new file mode 100644 index 0000000000..1b551245a3 --- /dev/null +++ b/OOXML/Binary/Sheets/Reader/CellFormatController/DateReader.h @@ -0,0 +1,44 @@ +/* + * (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 + * + */ + +#pragma once + +#include "../../../../Base/Base.h" + +#include + +class DateReader +{ +public: + _UINT32 GetDigitalDate(const std::wstring &date); +}; + diff --git a/OOXML/Binary/Sheets/Reader/XMLReader/XLSXTableController.h b/OOXML/Binary/Sheets/Reader/XMLReader/XLSXTableController.h index 8ec5de3d13..162a15b939 100644 --- a/OOXML/Binary/Sheets/Reader/XMLReader/XLSXTableController.h +++ b/OOXML/Binary/Sheets/Reader/XMLReader/XLSXTableController.h @@ -31,7 +31,7 @@ */ #pragma once -#include "../CellFormatController.h" +#include "../CellFormatController/CellFormatController.h" #include "../../../../Base/Base.h" #include "../../../../XlsxFormat/Worksheets/Worksheet.h" diff --git a/OOXML/Projects/Linux/BinDocument/BinDocument.pro b/OOXML/Projects/Linux/BinDocument/BinDocument.pro index ba8cd7619a..23ba6a7a89 100644 --- a/OOXML/Projects/Linux/BinDocument/BinDocument.pro +++ b/OOXML/Projects/Linux/BinDocument/BinDocument.pro @@ -67,7 +67,8 @@ SOURCES += \ ../../../Binary/Sheets/Reader/XMLReader/XMLConverter2.cpp \ ../../../Binary/Sheets/Reader/XMLReader/XMLMap.cpp \ ../../../Binary/Sheets/Reader/XMLReader/XMLReader2.cpp \ - ../../../Binary/Sheets/Reader/CellFormatController.cpp + ../../../Binary/Sheets/Reader/CellFormatController/CellFormatController.cpp \ + ../../../Binary/Sheets/Reader/CellFormatController/DateReader.cpp HEADERS += \ ../../../Binary/Document/DocWrapper/DocxSerializer.h \ @@ -111,4 +112,5 @@ HEADERS += \ ../../../Binary/Sheets/Reader/XMLReader/columnNameController.h \ ../../../Binary/Sheets/Reader/XMLReader/XMLConverter2.h \ ../../../Binary/Sheets/Reader/XMLReader/XMLMap.h \ - ../../../Binary/Sheets/Reader/CellFormatController.h + ../../../Binary/Sheets/Reader/CellFormatController/CellFormatController.h \ + ../../../Binary/Sheets/Reader/CellFormatController/DateReader.h