1#ifndef OPENXLSX_XLUTILITIES_HPP
2#define OPENXLSX_XLUTILITIES_HPP
31 unsigned char uc =
static_cast<unsigned char>(c);
32 if (uc < 0x20 && uc != 0x09 && uc != 0x0A && uc != 0x0D) {
47 result.reserve(sv.size());
49 unsigned char uc =
static_cast<unsigned char>(c);
50 if (uc >= 0x20 || uc == 0x09 || uc == 0x0A || uc == 0x0D) {
67 if (cellRef ==
nullptr or *cellRef ==
'\0')
return 0;
70 const char* p = cellRef;
73 while (*p >=
'A' and *p <=
'Z') {
74 colNo = colNo * 26 +
static_cast<uint32_t
>(*p -
'A' + 1);
79 return (colNo > 0 and colNo <=
MAX_COLS) ?
static_cast<uint16_t
>(colNo) : 0;
96 temp[idx++] =
static_cast<char>(
'A' + (colNo % 26));
102 while (idx > 0) { buffer[j++] = temp[--idx]; }
116 #if defined(__GNUC__) || defined(__clang__)
117__attribute__((always_inline))
inline char*
makeCellAddress(uint32_t row, uint16_t col,
char* buffer)
noexcept
118#elif defined(_MSC_VER)
119__forceinline
char*
makeCellAddress(uint32_t row, uint16_t col,
char* buffer)
noexcept
130 for (
const char* c = colLetters; *c; ++c) { *p++ = *c; }
137 rowStr[idx++] =
static_cast<char>(
'0' + (r % 10));
143 while (idx > 0) { *p++ = rowStr[--idx]; }
164 using namespace std::literals::string_literals;
191 using namespace std::literals::string_literals;
193 case pugi::node_null:
195 case pugi::node_document:
196 return "node_document"s;
197 case pugi::node_element:
198 return "node_element"s;
199 case pugi::node_pcdata:
200 return "node_pcdata"s;
201 case pugi::node_cdata:
202 return "node_cdata"s;
203 case pugi::node_comment:
204 return "node_comment"s;
207 case pugi::node_declaration:
208 return "node_declaration"s;
209 case pugi::node_doctype:
210 return "node_doctype"s;
227 return "Relationships";
229 return "WorkbookMacroEnabled";
235 return "ExternalLink";
241 return "SharedStrings";
249 return "ChartColorStyle";
251 return "ControlProperties";
253 return "CalculationChain";
259 return "SlicerCache";
263 return "PivotCacheDefinition";
265 return "PivotCacheRecords";
268 return "CoreProperties";
270 return "ExtendedProperties";
272 return "CustomProperties";
280 return "ThreadedComments";
301 return "CoreProperties";
303 return "ExtendedProperties";
305 return "CustomProperties";
313 return "Dialogsheet";
317 return "CalculationChain";
319 return "ExternalLink";
321 return "ExternalLinkPath";
331 return "ChartColorStyle";
339 return "SharedStrings";
341 return "PrinterSettings";
347 return "SlicerCache";
351 return "PivotCacheDefinition";
353 return "PivotCacheRecords";
356 return "ControlProperties";
362 return "ThreadedComments";
379 using namespace std::literals::string_literals;
380 throw XLCellAddressError(
"rowNumber "s + std::to_string(rowNumber) +
" is outside valid range [1;"s +
385 if (hintRowNumber && hintRowNode && *hintRowNumber == rowNumber && !hintRowNode->empty()) {
392 if (hintRowNumber && hintRowNode && !hintRowNode->empty() && rowNumber > *hintRowNumber) {
393 result = *hintRowNode;
394 while (!result.empty() && result.attribute(
"r").as_ullong() < rowNumber) {
397 if (result.empty() || result.attribute(
"r").as_ullong() > rowNumber) {
398 if (result.empty()) result = sheetDataNode.
append_child(
"row");
400 result.append_attribute(
"r") = rowNumber;
403 else if (hintRowNumber && hintRowNode && !hintRowNode->empty() && rowNumber < *hintRowNumber) {
404 result = *hintRowNode;
405 while (!result.empty() && result.attribute(
"r").as_ullong() > rowNumber) {
408 if (result.empty() || result.attribute(
"r").as_ullong() < rowNumber) {
409 if (result.empty()) result = sheetDataNode.
prepend_child(
"row");
411 result.append_attribute(
"r") = rowNumber;
418 if (result.empty() or (rowNumber > result.attribute(
"r").as_ullong())) {
420 result.append_attribute(
"r") = rowNumber;
422 else if (result.attribute(
"r").as_ullong() - rowNumber < rowNumber) {
423 while (not result.empty() and (result.attribute(
"r").as_ullong() > rowNumber))
425 if (result.empty() or (result.attribute(
"r").as_ullong() != rowNumber)) {
430 result.append_attribute(
"r") = rowNumber;
435 while (result.attribute(
"r").as_ullong() < rowNumber) result = result.
next_sibling_of_type(pugi::node_element);
436 if (result.attribute(
"r").as_ullong() > rowNumber) {
438 result.append_attribute(
"r") = rowNumber;
444 if (hintRowNumber && hintRowNode) {
445 *hintRowNumber = rowNumber;
446 *hintRowNode = result;
468 if (not cols.empty()) {
470 while (not col.empty()) {
471 int minCol = col.attribute(
"min").as_int(
MAX_COLS + 1);
472 int maxCol = col.attribute(
"max").as_int(0);
475 for (
int i = minCol; i <= maxCol && i <= count; ++i) {
476 if (i > 0) styles[i - 1] = style;
487 if (not cols.empty()) {
489 while (not col.empty()) {
490 if (col.attribute(
"min").as_int(
MAX_COLS + 1) <= colNo and col.attribute(
"max").as_int(0) >= colNo)
509 const std::string& cellRef,
512 std::vector<XLStyleIndex>
const& colStyles = {})
514 cellNode.append_attribute(
"r").set_value(cellRef.c_str());
517 if (rowStyle.empty()) {
518 if (colStyles.size() > 0)
528 cellNode.append_attribute(
"s").set_value(cellStyle);
539 std::vector<XLStyleIndex>
const& colStyles = {})
541 cellNode.append_attribute(
"r").set_value(cellRef);
544 if (rowStyle.empty()) {
545 if (colStyles.size() > 0)
567 uint16_t columnNumber,
568 uint32_t rowNumber = 0,
569 std::vector<XLStyleIndex>
const& colStyles = {},
570 uint16_t* hintColNumber =
nullptr,
571 XMLNode* hintCellNode =
nullptr)
574 using namespace std::literals::string_literals;
575 throw XLException(
"XLWorksheet::column: columnNumber "s + std::to_string(columnNumber) +
" is outside allowed range [1;"s +
578 if (rowNode.empty())
return XMLNode{};
580 if (!rowNumber) rowNumber = rowNode.attribute(
"r").as_uint();
583 if (hintColNumber && hintCellNode && *hintColNumber == columnNumber && !hintCellNode->empty() && hintCellNode->
parent() == rowNode) {
584 return *hintCellNode;
590 if (hintColNumber && hintCellNode && !hintCellNode->empty() && hintCellNode->
parent() == rowNode) {
591 cellNode = *hintCellNode;
592 if (columnNumber > *hintColNumber) {
593 uint16_t currentCol = *hintColNumber;
594 while (!cellNode.empty() && currentCol < columnNumber) {
598 if (currentCol > columnNumber || cellNode.empty()) {
599 if (cellNode.empty()) cellNode = rowNode.
append_child(
"c");
601 char cellAddrBuf[16];
607 else if (columnNumber < *hintColNumber) {
608 uint16_t currentCol = *hintColNumber;
609 while (!cellNode.empty() && currentCol > columnNumber) {
613 if (currentCol < columnNumber || cellNode.empty()) {
616 char cellAddrBuf[16];
629 if (cellNode.empty() or (lastCellCol < columnNumber)) {
631 char cellAddrBuf[16];
635 else if (lastCellCol - columnNumber < columnNumber) {
636 uint16_t currentCol = lastCellCol;
637 while (not cellNode.empty() and (currentCol > columnNumber)) {
641 if (cellNode.empty() or (currentCol < columnNumber)) {
644 char cellAddrBuf[16];
652 while (currentCol < columnNumber) {
656 if (currentCol > columnNumber) {
658 char cellAddrBuf[16];
666 if (hintColNumber && hintCellNode) {
667 *hintColNumber = columnNumber;
668 *hintCellNode = cellNode;
683 inline int findStringInVector(std::string
const& nodeName, std::vector<std::string_view>
const& nodeOrder)
685 for (
size_t i = 0; i < nodeOrder.size(); ++i)
686 if (nodeName == nodeOrder[i])
return static_cast<int>(i);
701 while (fromNode.type() == pugi::node_pcdata) {
703 toNode.set_value(fromNode.value());
719 std::string
const& nodeName,
720 std::vector<std::string_view>
const& nodeOrder = {},
721 bool force_ns =
false)
723 if (parent.empty())
return XMLNode{};
726 if (nextNode.empty())
738 if (not nextNode.empty()) {
739 if (nextNode.
name() == nodeName)
750 node = parent.
child(nodeName.c_str());
770 attr = node.append_attribute(attrName.c_str());
771 attr.set_value(attrDefaultVal.c_str());
780 if (attr.empty()) attr = node.append_attribute(attrName.c_str());
781 attr.set_value(attrVal.c_str());
795 std::string
const& nodeName,
796 std::string
const& attrName,
797 std::string
const& attrDefaultVal,
798 std::vector<std::string_view>
const& nodeOrder = {})
816 std::string
const& nodeName,
817 std::string
const& attrName,
818 std::string
const& attrVal,
820 std::vector<std::string_view>
const& nodeOrder = {})
824 if (removeAttributes) node.remove_attributes();
840 if (parent.empty())
return false;
842 if (tagNode.empty())
return false;
843 XMLAttribute valAttr = tagNode.attribute(attrName.c_str());
844 if (valAttr.empty()) {
849 return valAttr.as_bool();
859 if (data.size() < 8)
return {0, 0};
862 if (
reinterpret_cast<const uint8_t*
>(data.data())[0] == 0x89 and data.substr(1, 3) ==
"PNG") {
863 if (data.size() < 24)
return {0, 0};
865 const uint8_t* p =
reinterpret_cast<const uint8_t*
>(data.data());
866 uint32_t w = (
static_cast<uint32_t
>(p[16]) << 24) | (
static_cast<uint32_t
>(p[17]) << 16) | (
static_cast<uint32_t
>(p[18]) << 8) |
867 static_cast<uint32_t
>(p[19]);
868 uint32_t h = (
static_cast<uint32_t
>(p[20]) << 24) | (
static_cast<uint32_t
>(p[21]) << 16) | (
static_cast<uint32_t
>(p[22]) << 8) |
869 static_cast<uint32_t
>(p[23]);
874 if (
reinterpret_cast<const uint8_t*
>(data.data())[0] == 0xFF and
reinterpret_cast<const uint8_t*
>(data.data())[1] == 0xD8) {
876 while (offset + 4 < data.size()) {
877 const uint8_t* p =
reinterpret_cast<const uint8_t*
>(data.data()) + offset;
878 if (p[0] != 0xFF)
break;
879 uint8_t marker = p[1];
880 uint32_t length = (
static_cast<uint32_t
>(p[2]) << 8) |
static_cast<uint32_t
>(p[3]);
883 if ((marker >= 0xC0 and marker <= 0xC3) or (marker >= 0xC5 and marker <= 0xC7) or (marker >= 0xC9 and marker <= 0xCB) ||
884 (marker >= 0xCD and marker <= 0xCF))
886 if (offset + 9 > data.size())
return {0, 0};
888 uint32_t h = (
static_cast<uint32_t
>(p[5]) << 8) |
static_cast<uint32_t
>(p[6]);
889 uint32_t w = (
static_cast<uint32_t
>(p[7]) << 8) |
static_cast<uint32_t
>(p[8]);
892 offset += length + 2;
Definition XLXmlParser.hpp:84
XMLNode last_child_of_type(pugi::xml_node_type type_=pugi::node_element) const
get last node child that matches type
Definition XLXmlParser.cpp:63
XMLNode child(const pugi::char_t *name_) const
Definition XLXmlParser.hpp:150
XMLNode prepend_child(pugi::xml_node_type type_)
Definition XLXmlParser.hpp:161
XMLNode previous_sibling_of_type(pugi::xml_node_type type_=pugi::node_element) const
get previous node sibling that matches type
Definition XLXmlParser.cpp:95
XMLNode append_child(pugi::xml_node_type type_)
Definition XLXmlParser.hpp:160
XMLNode previous_sibling(const pugi::char_t *name_) const
Definition XLXmlParser.hpp:153
XMLNode next_sibling_of_type(pugi::xml_node_type type_=pugi::node_element) const
get next node sibling that matches type
Definition XLXmlParser.cpp:87
XMLNode insert_child_before(pugi::xml_node_type type_, const xml_node &node)
Definition XLXmlParser.hpp:167
XMLNode insert_child_after(pugi::xml_node_type type_, const xml_node &node)
Definition XLXmlParser.hpp:166
const pugi::char_t * name() const
get node name while stripping namespace, if so configured (name_begin > 0)
Definition XLXmlParser.hpp:135
XMLNode parent() const
for all functions returning xml_node: invoke base class function, but with a return type of XMLNode (...
Definition XLXmlParser.hpp:146
XMLNode first_child_of_type(pugi::xml_node_type type_=pugi::node_element) const
get first node child that matches type
Definition XLXmlParser.cpp:52
Definition XLException.hpp:50
Definition XLException.hpp:23
Definition XLException.hpp:68
Definition IZipArchive.hpp:18
std::string XLValueTypeString(XLValueType t)
Get a string representation of pugi::xml_node_type.
Definition XLUtilities.hpp:162
constexpr uint32_t MAX_ROWS
Definition XLConstants.hpp:9
void ignore(const T &)
Get rid of compiler warnings about unused variables (-Wunused-variable) or unused parameters (-Wunusu...
Definition XLUtilities.hpp:154
void copyLeadingWhitespaces(XMLNode &parent, XMLNode fromNode, XMLNode toNode)
copy all leading pc_data nodes from fromNode to toNode
Definition XLUtilities.hpp:697
XMLAttribute appendAndSetNodeAttribute(XMLNode &parent, std::string const &nodeName, std::string const &attrName, std::string const &attrVal, bool removeAttributes=XLKeepAttributes, std::vector< std::string_view > const &nodeOrder={})
ensure that node with nodeName exists in parent, has an attribute with attrName, set attribute value ...
Definition XLUtilities.hpp:815
std::string XLContentTypeString(OpenXLSX::XLContentType const &t)
Get a string representation of OpenXLSX::XLContentType.
Definition XLUtilities.hpp:220
constexpr const XLStyleIndex XLDefaultCellFormat
Definition XLStyles.hpp:49
std::string xml_node_type_string(pugi::xml_node_type t)
Get a string representation of pugi::xml_node_type.
Definition XLUtilities.hpp:189
constexpr const bool XLRemoveAttributes
Definition XLUtilities.hpp:20
XLContentType
Definition XLContentTypes.hpp:28
XLRelationshipType
An enum of the possible relationship (or XML document) types used in relationship (....
Definition XLRelationships.hpp:58
pugi::xml_attribute XMLAttribute
Definition XLXmlParser.hpp:64
size_t XLStyleIndex
Definition XLStyles.hpp:31
char * makeCellAddress(uint32_t row, uint16_t col, char *buffer) noexcept
Generate cell address string directly without creating XLCellReference object. Performance optimizati...
Definition XLUtilities.hpp:121
void setDefaultCellAttributes(XMLNode cellNode, const std::string &cellRef, XMLNode rowNode, uint16_t colNo, std::vector< XLStyleIndex > const &colStyles={})
set the cell reference, and a default cell style attribute if and only if row or column style is !...
Definition XLUtilities.hpp:508
constexpr uint16_t MAX_COLS
Definition XLConstants.hpp:8
XMLAttribute appendAndGetAttribute(XMLNode &node, std::string const &attrName, std::string const &attrDefaultVal)
Definition XLUtilities.hpp:765
XLStyleIndex getColumnStyle(XMLNode rowNode, uint16_t colNo)
Definition XLUtilities.hpp:484
int findStringInVector(std::string const &nodeName, std::vector< std::string_view > const &nodeOrder)
Definition XLUtilities.hpp:683
XLValueType
Enum defining the valid value types for a an Excel spreadsheet cell.
Definition XLCellValue.hpp:37
std::string XLRelationshipTypeString(OpenXLSX::XLRelationshipType const &t)
Get a string representation of OpenXLSX::XLRelationshipType.
Definition XLUtilities.hpp:296
XMLAttribute appendAndGetNodeAttribute(XMLNode &parent, std::string const &nodeName, std::string const &attrName, std::string const &attrDefaultVal, std::vector< std::string_view > const &nodeOrder={})
ensure that node with nodeName exists in parent, has an attribute with attrName and return that attri...
Definition XLUtilities.hpp:794
constexpr const int SORT_INDEX_NOT_FOUND
find the index of nodeName in nodeOrder
Definition XLUtilities.hpp:682
std::vector< XLStyleIndex > getColumnStyles(XMLNode rowNode, uint16_t count)
get the style attribute s for the indicated column, if any is set
Definition XLUtilities.hpp:464
std::pair< uint32_t, uint32_t > getImageDimensions(const std::string &data)
Extract image dimensions (width and height) from raw image data (PNG/JPEG)
Definition XLUtilities.hpp:857
bool isCleanXmlString(std::string_view sv) noexcept
Checks if a string contains only valid XML 1.0 characters.
Definition XLUtilities.hpp:28
XMLAttribute appendAndSetAttribute(XMLNode &node, std::string const &attrName, std::string const &attrVal)
Definition XLUtilities.hpp:776
XMLNode getCellNode(XMLNode rowNode, uint16_t columnNumber, uint32_t rowNumber=0, std::vector< XLStyleIndex > const &colStyles={}, uint16_t *hintColNumber=nullptr, XMLNode *hintCellNode=nullptr)
Retrieve the xml node representing the cell at the given row and column. If the node doesn't exist,...
Definition XLUtilities.hpp:566
XMLNode getRowNode(XMLNode sheetDataNode, uint32_t rowNumber, uint32_t *hintRowNumber=nullptr, XMLNode *hintRowNode=nullptr)
Definition XLUtilities.hpp:376
char * columnToLetters(uint16_t colNo, char *buffer) noexcept
Convert column number to column letter string (A, B, ..., Z, AA, AB, ..., XFD) Performance optimizati...
Definition XLUtilities.hpp:89
bool getBoolAttributeWhenOmittedMeansTrue(XMLNode &parent, std::string const &tagName, std::string const &attrName="val")
special bool attribute getter function for tags that should have a val="true" or val="false" attribut...
Definition XLUtilities.hpp:838
XMLNode appendAndGetNode(XMLNode &parent, std::string const &nodeName, std::vector< std::string_view > const &nodeOrder={}, bool force_ns=false)
ensure that node with nodeName exists in parent and return it
Definition XLUtilities.hpp:718
std::string sanitizeXmlString(std::string_view sv)
Removes invalid XML 1.0 control characters from a string to prevent file corruption.
Definition XLUtilities.hpp:44
uint16_t extractColumnFromCellRef(const char *cellRef) noexcept
Lightweight function to extract column number from a cell reference string. This is a performance-opt...
Definition XLUtilities.hpp:65
constexpr const bool XLKeepAttributes
Definition XLUtilities.hpp:21