/* * (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 "HelpFunc.h" #include "../../../../UnicodeConverter/UnicodeConverter.h" #include "../Logic/Biff_structures/CellRangeRef.h" #include "../Logic/GlobalWorkbookInfo.h" #include #include #include #if defined(_WIN32) || defined(__WIN64) #include "Windows.h" #else //#include "iconv.h" .. to UnicodeConverter #endif namespace AUX { const int normalizeColumn(const int column, const bool xlsb) { int maxCol = 0; if(xlsb) { maxCol = 16383; } else { maxCol = 255; } int norm_col = column; while (norm_col > maxCol) { norm_col -= (maxCol+1); } while (norm_col < 0) { norm_col += (maxCol+1); // It is correct. must be on the second place after maxCol(16383 or 255) } return norm_col; } const std::wstring column2str(const int column, const bool col_rel, const bool xlsb) { int column_value = normalizeColumn(column, xlsb); const int radix = L'Z' - L'A' + 1; std::wstring ret_val; ++column_value; while(column_value) { wchar_t sym = (column_value - 1) % radix + L'A'; ret_val = sym + ret_val; column_value = (column_value - 1) / radix; } return (col_rel ? L"" : L"$") + ret_val; } const int normalizeRow(const int row, const bool xlsb) { int maxRow = 0; if(xlsb) { maxRow = 1048576; } else { maxRow = 65536; } int norm_row = row; while(norm_row >= maxRow) { norm_row -= maxRow; } while(norm_row < 0) { norm_row += maxRow; // It is correct. must be on the second place after 1048576 } return norm_row; } const std::wstring row2str(const int row, const bool row_rel, const bool xlsb) { int row_value = normalizeRow(row, xlsb); return (row_rel ? L"" : L"$") + STR::int2wstr(row_value + 1, 10); } const std::wstring loc2str(const int row, const bool row_rel, const int column, const bool col_rel, const bool xlsb) { return column2str(column, col_rel, xlsb) + row2str(row, row_rel, xlsb); } const int str2column(std::wstring::const_iterator& str_begin, std::wstring::const_iterator& str_end) { const int radix = L'Z' - L'A' + 1; int column = -1; for(; str_begin != str_end; ++str_begin) { const wchar_t symb = *str_begin; if(L'A' > symb || L'Z' < symb) { break; } column = (column + 1) * radix + (symb - L'A'); } if(column > 16383) { column = 16383; } return column; } const int str2row(std::wstring::const_iterator& str_begin, std::wstring::const_iterator& str_end) { int row = 0; for(; str_begin != str_end; ++str_begin) { const wchar_t symb = *str_begin; if(L'0' > symb || L'9' < symb) { break; } row = row * 10 + (symb - L'0'); } --row; if(row > 1048575) { row = 1048575; } return row; } const bool str2rel(std::wstring::const_iterator& str_begin, std::wstring::const_iterator& str_end) { if(str_begin != str_end && L'$' == *str_begin) { ++str_begin; return false; } return true; } void str2loc(std::wstring::const_iterator& str_begin, std::wstring::const_iterator& str_end, int& row, bool& row_rel, int& column, bool& col_rel) { col_rel = str2rel (str_begin, str_end); column = str2column (str_begin, str_end); row_rel = str2rel (str_begin, str_end); row = str2row (str_begin, str_end); } void str2loc(const std::wstring& str, int& row, bool& row_rel, int& column, bool& col_rel) { std::wstring::const_iterator str_begin = str.begin(); std::wstring::const_iterator str_end = str.end(); str2loc(str_begin, str_end, row, row_rel, column, col_rel); } void str2refs(const std::wstring& str, std::vector& vec) { std::wstring str_left(str); do { XLS::CellRangeRef ref1(str_left); vec.push_back(ref1); size_t next_pos = str_left.find_first_of(L' '); if(std::wstring::npos == next_pos) { break; } str_left = str_left.substr(next_pos + 1, str_left.length() - next_pos - 1); } while(str_left.length()); } } //namespace AUX namespace STR {; const std::string int2str(const int val, const int radix) { static char num_buf[10]={}; #if defined(_WIN32) || defined(_WIN64) _itoa_s(val, num_buf, 9, radix); #else sprintf( num_buf, "%d", val); #endif return num_buf; } const std::wstring int2wstr(const int val, const int radix) { #if defined(_WIN32) || defined(_WIN64) static wchar_t num_buf[20]={}; _itow_s(val, num_buf, 19, radix); return std::wstring(num_buf); #else static char num_buf[20]={}; sprintf( num_buf, "%d", val); std::string a_str(num_buf); return std::wstring(a_str.begin(), a_str.end()); #endif } const std::wstring double2str(const double val) { return boost::lexical_cast(val);// std::to_wstring(val); - rounding ( } const std::string bin2str(const char* buf, const size_t nbuf) { static const char hex[17] = "0123456789ABCDEF"; std::vector code_string(nbuf * 3 + 1); size_t idx = 0; for(size_t i = 0; i < nbuf; ++i) { code_string[idx++] = '%'; code_string[idx++] = hex[(buf[i] & 0xf0) >> 4]; code_string[idx++] = hex[buf[i] & 0x0f]; } code_string[idx] = 0; return &code_string[0]; } const std::wstring guid2bstr(_GUID_ & guid) { std::wstring guid_ret=L"{"; guid_ret += int2hex_wstr(guid.Data1, 4) + L"-" + int2hex_wstr(guid.Data2, 2) + L"-" + int2hex_wstr(guid.Data3, 2) + L"-" + int2hex_wstr((guid.getData4())[0], 1) + int2hex_wstr((guid.getData4())[1], 1) + L"-" + int2hex_wstr((guid.getData4())[2], 1) + int2hex_wstr((guid.getData4())[3], 1) + int2hex_wstr((guid.getData4())[4], 1) + int2hex_wstr((guid.getData4())[5], 1) + int2hex_wstr((guid.getData4())[6], 1) + int2hex_wstr((guid.getData4())[7], 1); return guid_ret + L"}"; } const std::string guid2str(_GUID_ & guid) { std::wstring s = guid2bstr(guid); return std::string(s.begin(), s.end()); } const std::wstring guidFromStr(const std::wstring & guid_str) { boost::wregex match_guid(L"[A-Za-z0-9_]{8}-[A-Za-z0-9_]{4}-[A-Za-z0-9_]{4}-[A-Za-z0-9_]{4}-[A-Za-z0-9_]{12}"); boost::wsmatch result; if(boost::regex_search(guid_str, result, match_guid)) { return result.str(); } return L""; } const bool bstr2guid(const std::wstring & guid_str, _GUID_& guid) { std::wstring guid_str_copy = guid_str; if(*guid_str_copy.begin() == L'{') guid_str_copy.erase(guid_str_copy.begin()); if (*(guid_str_copy.end() - 1) == L'}') guid_str_copy.erase(guid_str_copy.end() - 1); guid.Data1 = hex_str2int(guid_str_copy.substr(0, 8)); guid.Data2 = hex_str2int(guid_str_copy.substr(9, 4)); guid.Data3 = hex_str2int(guid_str_copy.substr(14, 4)); BYTE data4[8]; data4[0] = hex_str2int(guid_str_copy.substr(19, 2)); data4[1] = hex_str2int(guid_str_copy.substr(21, 2)); data4[2] = hex_str2int(guid_str_copy.substr(24, 2)); data4[3] = hex_str2int(guid_str_copy.substr(26, 2)); data4[4] = hex_str2int(guid_str_copy.substr(28, 2)); data4[5] = hex_str2int(guid_str_copy.substr(30, 2)); data4[6] = hex_str2int(guid_str_copy.substr(32, 2)); data4[7] = hex_str2int(guid_str_copy.substr(34, 2)); memcpy(&guid.Data4, data4, 8); return false; } const std::wstring int2hex_wstr(const int val, const size_t size_of) { if(size_of > 4) return L""; #if defined(_WIN32) || defined(_WIN64) static wchar_t num_buf[10]={}; std::wstring wstr = STR::int2wstr(size_of << 1, 10); swprintf_s(num_buf, 9, (L"%0" + wstr + L"X").c_str(), val); return std::wstring(num_buf); #else char num_buf[10]={}; std::string str = STR::int2str(size_of << 1, 10); snprintf(num_buf, 9, ("%0" + str + "X").c_str(), val); std::string res(num_buf); return std::wstring(res.begin(), res.end()); #endif } const std::wstring wchar_t2hex_str(const wchar_t val) { static const wchar_t hex[17] = L"0123456789ABCDEF"; wchar_t code_string[5]; code_string[0] = hex[(val & 0xf000) >> 12]; code_string[1] = hex[(val & 0x0f00) >> 8]; code_string[2] = hex[(val & 0x00f0) >> 4]; code_string[3] = hex[(val & 0x000f)]; code_string[4] = 0; return code_string; } const std::wstring escape_ST_Xstring(const std::wstring& wstr) { static boost::wregex match_hex(L"^_x[0-9A-F]{4}_"); std::wstring ret_val = L""; for (size_t i = 0; i < wstr.length(); i++) { wchar_t in_symb = wstr[i]; if (in_symb < 0x0009 || in_symb == 0x000B || in_symb == 0x000C || in_symb > 0x000D && in_symb < 0x0020 || in_symb > 0xD7FF && in_symb < 0xE000 || in_symb > 0xFFFD) { ret_val += L"_x" + wchar_t2hex_str(in_symb) + L"_"; } else if(L'_' == in_symb && boost::regex_search(std::wstring(wstr, i, 7), match_hex)) { ret_val += L"_x005F_"; } else { ret_val += in_symb; } } return ret_val; } const std::wstring unescape_ST_Xstring(const std::wstring& wstr) { static boost::wregex match_hex(L"^_x[0-9A-F]{4}_"); std::wstring::const_iterator x_pos_noncopied = wstr.begin(); std::wstring::const_iterator x_pos_next;// = wstr.begin(); std::wstring::const_iterator wstr_end = wstr.end(); std::wstring ret_val = L""; while(true) { const auto it_range = boost::make_iterator_range(x_pos_noncopied, wstr_end); x_pos_next = boost::algorithm::find_first(it_range, L"_x").begin(); if ( wstr_end == x_pos_next) break; if(!boost::regex_search(x_pos_next, wstr_end, match_hex)) { x_pos_next += 2; ret_val.append(x_pos_noncopied, x_pos_next); x_pos_noncopied = x_pos_next; } else { ret_val += static_cast(hex_str2int(x_pos_next + 2, x_pos_next + 6)); x_pos_noncopied = x_pos_next + 7; } } ret_val.append(x_pos_noncopied, x_pos_next); return ret_val; } const std::wstring toARGB(const _UINT32 rgba) { return toARGB(static_cast(rgba & 0xff), static_cast((rgba >> 8) & 0xff), static_cast((rgba >> 16) & 0xff), static_cast((rgba >> 24) & 0xff)); } const std::wstring toRGB(const _UINT32 rgba) { unsigned char R = static_cast((rgba >> 16) & 0xff); unsigned char G = static_cast((rgba >> 8) & 0xff); unsigned char B = static_cast(rgba & 0xff); return toRGB(R, G ,B); } const std::wstring toARGB(const unsigned char red, const unsigned char green, const unsigned char blue, const unsigned char alpha) { return int2hex_wstr(alpha, sizeof(alpha)) + toRGB(red, green, blue); } const std::wstring toRGB(const unsigned char red, const unsigned char green, const unsigned char blue) { return int2hex_wstr(red, sizeof(red)) + int2hex_wstr(green,sizeof(green)) + int2hex_wstr(blue,sizeof(blue)); } const bool fromARGB(const std::wstring& argb, unsigned char& red, unsigned char& green, unsigned char& blue, unsigned char& alpha) { if(argb.length() < 8) { return false; } alpha = static_cast (hex_str2int(argb.substr(0, 2))); red = static_cast (hex_str2int(argb.substr(2, 2))); green = static_cast (hex_str2int(argb.substr(4, 2))); blue = static_cast (hex_str2int(argb.substr(6, 2))); return true; } const int HexChar2Int(const char value) { if (value >= '0' && value <= '9') return value - '0'; if (value >= 'a' && value <= 'f') return 10 + value - 'a'; if (value >= 'A' && value <= 'F') return 10 + value - 'A'; return 0; } const size_t hex_str2int(const std::wstring& hex) { size_t summa = 0; for (int i = 0; i != hex.length(); ++i) summa += HexChar2Int((char)hex[i]) << (4 * (hex.length() - i - 1)); return summa; } const size_t hex_str2int(const std::wstring::const_iterator& it_begin, const std::wstring::const_iterator& it_end) { static const std::wstring hex_digits(L"0123456789ABCDEF"); size_t numeric = 0; for(std::wstring::const_iterator it = it_begin, itEnd = it_end; it != itEnd; ++it) { size_t pos = hex_digits.find_first_of(*it); if(std::wstring::npos == pos) { break; } numeric = numeric * 16 + pos; } return numeric; } //std::wstring toStdWStringSystem(std::string ansi_string, const unsigned int code_page) .. to UnicodeConverter //{ // bool ansi = true; // std::wstring sResult; // // size_t insize = ansi_string.length(); // char* inptr = (char*)ansi_string.c_str(); // // if (code_page > 0) // { //#if defined (_WIN32) || defined (_WIN64) // int outsize_with_0 = MultiByteToWideChar(code_page, 0, inptr, -1, NULL, NULL); // sResult.resize(outsize_with_0); // if (MultiByteToWideChar(code_page, 0, inptr, -1, (LPWSTR)sResult.c_str(), outsize_with_0) > 0) // { // sResult.erase(outsize_with_0 - 1); // ansi = false; // } //#elif defined(__linux__) // std::string sCodepage = "CP" + std::to_string(code_page); // // iconv_t ic= iconv_open("WCHAR_T", sCodepage.c_str()); // if (ic != (iconv_t) -1) // { // sResult.resize(insize); // char* outptr = (char*)sResult.c_str(); // // size_t nconv = 0, avail = (insize) * sizeof(wchar_t), outsize = insize; // nconv = iconv (ic, &inptr, &insize, &outptr, &avail); // if (nconv == 0) // { // if (avail > 0) // { // outsize = outsize - avail/sizeof(wchar_t); // sResult.erase(sResult.begin() + outsize); // } // ansi = false; // } // iconv_close(ic); // } //#endif // } // if (ansi) // sResult = std::wstring(ansi_string.begin(), ansi_string.end()); // // return sResult; //} std::wstring toStdWString(std::string ansi_string, const _UINT32 code_page) { std::string sCodePage; std::map::const_iterator pFind = NSUnicodeConverter::mapEncodingsICU.find(code_page); if (pFind != NSUnicodeConverter::mapEncodingsICU.end()) { sCodePage = pFind->second; } if (!sCodePage.empty()) { NSUnicodeConverter::CUnicodeConverter oConverter; return oConverter.toUnicode(ansi_string, sCodePage.c_str()); } else if (code_page != 0) { NSUnicodeConverter::CUnicodeConverter oConverter; return oConverter.toUnicode(ansi_string, code_page); } else { std::locale loc(""); std::ctype const &facet = std::use_facet >(loc); std::wstring result; result.resize(ansi_string.size()); facet.widen(ansi_string.c_str(), ansi_string.c_str() + ansi_string.size(), &result[0]); return result; } } std::wstring toStdWString(char* ansi, int size, const _UINT32 code_page) { std::string sCodePage; std::map::const_iterator pFind = NSUnicodeConverter::mapEncodingsICU.find(code_page); if (pFind != NSUnicodeConverter::mapEncodingsICU.end()) { sCodePage = pFind->second; } if (!sCodePage.empty()) { NSUnicodeConverter::CUnicodeConverter oConverter; return oConverter.toUnicode(ansi, (_UINT32)size, sCodePage.c_str()); } else { NSUnicodeConverter::CUnicodeConverter oConverter; return oConverter.toUnicode(ansi, (_UINT32)size, code_page); } } std::string toStdString(std::wstring wide_string, const _UINT32 code_page) { std::string sCodePage; std::map::const_iterator pFind = NSUnicodeConverter::mapEncodingsICU.find(code_page); if (pFind != NSUnicodeConverter::mapEncodingsICU.end()) { sCodePage = pFind->second; } if (sCodePage.empty() && code_page > 0) { sCodePage = "CP" + std::to_string(code_page); } NSUnicodeConverter::CUnicodeConverter oConverter; return oConverter.fromUnicode(wide_string, sCodePage.c_str()); } } // namespace STR namespace XMLSTUFF {; const std::wstring tab2sheet_name(const short tabid, std::vector& sheets_names) { if(tabid >= 0 && static_cast(tabid) < sheets_names.size()) { return sheets_names[tabid]; } return L"#REF"; } const std::wstring name2sheet_name(std::wstring name, const std::wstring prefix) { static boost::wregex correct_sheet_name(L"^\\'.+?\\'$"); static boost::wregex test_sheet_name(L"[\\s)(\\!\\'&:-]+"); //.??? 6442946.xls std::wstring sheet_first = prefix + name; if(!boost::regex_search(sheet_first.begin(), sheet_first.end(), correct_sheet_name)) { if(boost::regex_search(sheet_first.begin(), sheet_first.end(), test_sheet_name)) { sheet_first = boost::algorithm::replace_all_copy(sheet_first, L"'", L"''"); sheet_first = std::wstring(L"'") + sheet_first + std::wstring(L"'"); } } return sheet_first; } const std::wstring xti_indexes2sheet_name(const short tabFirst, const short tabLast, std::vector& names, const std::wstring prefix) { if(-1 == tabFirst) { return L"#REF"; } static boost::wregex correct_table_name(L"^\\'.+?\\'$"); static boost::wregex test_table_name(L"([\\s)(\\!\\'&:-]+)|(^[\\d]+)"); //.??? 6442946.xls 5558608.xls std::wstring table_name = tab2sheet_name(tabFirst, names); std::wstring sheet_first = prefix + table_name; if(!boost::regex_search(table_name.begin(), table_name.end(), correct_table_name)) { if(boost::regex_search(table_name.begin(), table_name.end(), test_table_name)) { sheet_first = boost::algorithm::replace_all_copy(sheet_first, L"'", L"''"); sheet_first = std::wstring(L"'") + sheet_first + std::wstring(L"'"); } } std::wstring sheet_last; if (tabLast != tabFirst) { table_name = tab2sheet_name(tabLast, names); sheet_last = std::wstring(L":") + prefix + table_name; if(!boost::regex_search(table_name.begin(), table_name.end(), correct_table_name)) { if(boost::regex_search(table_name.begin(), table_name.end(), test_table_name)) { sheet_last = boost::algorithm::replace_all_copy(sheet_last, L"'", L"''"); sheet_last = std::wstring(L"'") + sheet_last + std::wstring(L"'"); } } } return sheet_first + sheet_last; } unsigned short sheetsnames2ixti(std::wstring name) { auto pos = std::find_if(XLS::GlobalWorkbookInfo::arXti_External_static.cbegin(), XLS::GlobalWorkbookInfo::arXti_External_static.cend(), [&](XLS::GlobalWorkbookInfo::_xti i) { return boost::algorithm::erase_last_copy(boost::algorithm::erase_first_copy(i.link, L"'"), L"'") == name; }); if (pos != XLS::GlobalWorkbookInfo::arXti_External_static.cend()) return pos->iSup; return 0xFFFF; } unsigned short AddMultysheetXti(const std::wstring& name, const _INT32& firstIxti, const _INT32& secondIxti) { auto pos1 = std::find_if(XLS::GlobalWorkbookInfo::arXti_External_static.cbegin(), XLS::GlobalWorkbookInfo::arXti_External_static.cend(), [&](XLS::GlobalWorkbookInfo::_xti i) { return i.iSup == firstIxti; }); auto pos2 = std::find_if(XLS::GlobalWorkbookInfo::arXti_External_static.cbegin(), XLS::GlobalWorkbookInfo::arXti_External_static.cend(), [&](XLS::GlobalWorkbookInfo::_xti i) { return i.iSup == secondIxti; }); if (pos1 == XLS::GlobalWorkbookInfo::arXti_External_static.cend() || pos2 == XLS::GlobalWorkbookInfo::arXti_External_static.cend()) return 0; XLS::GlobalWorkbookInfo::_xti newXti; newXti.iSup = XLS::GlobalWorkbookInfo::arXti_External_static.size(); newXti.itabFirst = pos1->itabFirst; newXti.itabLast = pos2->itabFirst; newXti.link = name; XLS::GlobalWorkbookInfo::arXti_External_static.push_back(newXti); return newXti.iSup; } unsigned int AddDefinedName(const std::wstring& name) { XLS::GlobalWorkbookInfo::arDefineNames_static.push_back(name); return (XLS::GlobalWorkbookInfo::arDefineNames_static.size()); } unsigned int definenames2index(std::wstring name) { unsigned int index; auto pos = std::find(XLS::GlobalWorkbookInfo::arDefineNames_static.cbegin(), XLS::GlobalWorkbookInfo::arDefineNames_static.cend(), name); if (pos != XLS::GlobalWorkbookInfo::arDefineNames_static.cend()) { index = pos - XLS::GlobalWorkbookInfo::arDefineNames_static.cbegin() + 1; return index; } return 0xFFFFFFFF; } bool isTableFmla(const std::wstring& tableName, _UINT32& listIndex) { for(const auto& item : XLS::GlobalWorkbookInfo::mapTableNames_static) { if (tableName == item.second) { listIndex = item.first; return true; } } return false; } bool isColumn(const std::wstring& columnName, _UINT32 listIndex, _UINT16& indexColumn) { const auto& arrColumn = XLS::GlobalWorkbookInfo::mapTableColumnNames_static.find(listIndex); if(arrColumn != XLS::GlobalWorkbookInfo::mapTableColumnNames_static.end()) { indexColumn = -1; auto unqotedName = columnName; if(!unqotedName.empty() && unqotedName.at(0) == '\'') unqotedName = unqotedName.substr(1, unqotedName.size() - 1); for (const auto& itemColumn : arrColumn->second) { ++indexColumn; if (unqotedName == itemColumn) { return true; } } } return false; } } //namespace XMLSTUFF