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) {
98 if (cellRef ==
nullptr or *cellRef ==
'\0')
return 0;
101 const char* p = cellRef;
104 while (*p >=
'A' and *p <=
'Z') {
105 colNo = colNo * 26 +
static_cast<uint32_t
>(*p -
'A' + 1);
110 return (colNo > 0 and colNo <=
MAX_COLS) ?
static_cast<uint16_t
>(colNo) : 0;
127 temp[idx++] =
static_cast<char>(
'A' + (colNo % 26));
133 while (idx > 0) { buffer[j++] = temp[--idx]; }
147 #if defined(__GNUC__) || defined(__clang__)
148__attribute__((always_inline))
inline char*
makeCellAddress(uint32_t row, uint16_t col,
char* buffer)
noexcept
149#elif defined(_MSC_VER)
150__forceinline
char*
makeCellAddress(uint32_t row, uint16_t col,
char* buffer)
noexcept
161 for (
const char* c = colLetters; *c; ++c) { *p++ = *c; }
168 rowStr[idx++] =
static_cast<char>(
'0' + (r % 10));
174 while (idx > 0) { *p++ = rowStr[--idx]; }
195 using namespace std::literals::string_literals;
222 using namespace std::literals::string_literals;
224 case pugi::node_null:
226 case pugi::node_document:
227 return "node_document"s;
228 case pugi::node_element:
229 return "node_element"s;
230 case pugi::node_pcdata:
231 return "node_pcdata"s;
232 case pugi::node_cdata:
233 return "node_cdata"s;
234 case pugi::node_comment:
235 return "node_comment"s;
238 case pugi::node_declaration:
239 return "node_declaration"s;
240 case pugi::node_doctype:
241 return "node_doctype"s;
258 return "Relationships";
260 return "WorkbookMacroEnabled";
266 return "ExternalLink";
272 return "SharedStrings";
280 return "ChartColorStyle";
282 return "ControlProperties";
284 return "CalculationChain";
290 return "SlicerCache";
294 return "PivotCacheDefinition";
296 return "PivotCacheRecords";
299 return "CoreProperties";
301 return "ExtendedProperties";
303 return "CustomProperties";
311 return "ThreadedComments";
332 return "CoreProperties";
334 return "ExtendedProperties";
336 return "CustomProperties";
344 return "Dialogsheet";
348 return "CalculationChain";
350 return "ExternalLink";
352 return "ExternalLinkPath";
362 return "ChartColorStyle";
370 return "SharedStrings";
372 return "PrinterSettings";
378 return "SlicerCache";
382 return "PivotCacheDefinition";
384 return "PivotCacheRecords";
387 return "ControlProperties";
393 return "ThreadedComments";
410 using namespace std::literals::string_literals;
411 throw XLCellAddressError(
"rowNumber "s + std::to_string(rowNumber) +
" is outside valid range [1;"s +
416 if (hintRowNumber && hintRowNode && *hintRowNumber == rowNumber && !hintRowNode->empty()) {
423 if (hintRowNumber && hintRowNode && !hintRowNode->empty() && rowNumber > *hintRowNumber) {
424 result = *hintRowNode;
425 while (!result.empty() && result.attribute(
"r").as_ullong() < rowNumber) {
428 if (result.empty() || result.attribute(
"r").as_ullong() > rowNumber) {
429 if (result.empty()) result = sheetDataNode.
append_child(
"row");
431 result.append_attribute(
"r") = rowNumber;
434 else if (hintRowNumber && hintRowNode && !hintRowNode->empty() && rowNumber < *hintRowNumber) {
435 result = *hintRowNode;
436 while (!result.empty() && result.attribute(
"r").as_ullong() > rowNumber) {
439 if (result.empty() || result.attribute(
"r").as_ullong() < rowNumber) {
440 if (result.empty()) result = sheetDataNode.
prepend_child(
"row");
442 result.append_attribute(
"r") = rowNumber;
449 if (result.empty() or (rowNumber > result.attribute(
"r").as_ullong())) {
451 result.append_attribute(
"r") = rowNumber;
453 else if (result.attribute(
"r").as_ullong() - rowNumber < rowNumber) {
454 while (not result.empty() and (result.attribute(
"r").as_ullong() > rowNumber))
456 if (result.empty() or (result.attribute(
"r").as_ullong() != rowNumber)) {
461 result.append_attribute(
"r") = rowNumber;
466 while (result.attribute(
"r").as_ullong() < rowNumber) result = result.
next_sibling_of_type(pugi::node_element);
467 if (result.attribute(
"r").as_ullong() > rowNumber) {
469 result.append_attribute(
"r") = rowNumber;
475 if (hintRowNumber && hintRowNode) {
476 *hintRowNumber = rowNumber;
477 *hintRowNode = result;
499 if (not cols.empty()) {
501 while (not col.empty()) {
502 int minCol = col.attribute(
"min").as_int(
MAX_COLS + 1);
503 int maxCol = col.attribute(
"max").as_int(0);
506 for (
int i = minCol; i <= maxCol && i <= count; ++i) {
507 if (i > 0) styles[i - 1] = style;
518 if (not cols.empty()) {
520 while (not col.empty()) {
521 if (col.attribute(
"min").as_int(
MAX_COLS + 1) <= colNo and col.attribute(
"max").as_int(0) >= colNo)
540 const std::string& cellRef,
543 std::vector<XLStyleIndex>
const& colStyles = {})
545 cellNode.append_attribute(
"r").set_value(cellRef.c_str());
548 if (rowStyle.empty()) {
549 if (colStyles.size() > 0)
559 cellNode.append_attribute(
"s").set_value(cellStyle);
570 std::vector<XLStyleIndex>
const& colStyles = {})
572 cellNode.append_attribute(
"r").set_value(cellRef);
575 if (rowStyle.empty()) {
576 if (colStyles.size() > 0)
598 uint16_t columnNumber,
599 uint32_t rowNumber = 0,
600 std::vector<XLStyleIndex>
const& colStyles = {},
601 uint16_t* hintColNumber =
nullptr,
602 XMLNode* hintCellNode =
nullptr)
605 using namespace std::literals::string_literals;
606 throw XLException(
"XLWorksheet::column: columnNumber "s + std::to_string(columnNumber) +
" is outside allowed range [1;"s +
609 if (rowNode.empty())
return XMLNode{};
611 if (!rowNumber) rowNumber = rowNode.attribute(
"r").as_uint();
614 if (hintColNumber && hintCellNode && *hintColNumber == columnNumber && !hintCellNode->empty() && hintCellNode->
parent() == rowNode) {
615 return *hintCellNode;
621 if (hintColNumber && hintCellNode && !hintCellNode->empty() && hintCellNode->
parent() == rowNode) {
622 cellNode = *hintCellNode;
623 if (columnNumber > *hintColNumber) {
624 uint16_t currentCol = *hintColNumber;
625 while (!cellNode.empty() && currentCol < columnNumber) {
629 if (currentCol > columnNumber || cellNode.empty()) {
630 if (cellNode.empty()) cellNode = rowNode.
append_child(
"c");
632 char cellAddrBuf[16];
638 else if (columnNumber < *hintColNumber) {
639 uint16_t currentCol = *hintColNumber;
640 while (!cellNode.empty() && currentCol > columnNumber) {
644 if (currentCol < columnNumber || cellNode.empty()) {
647 char cellAddrBuf[16];
660 if (cellNode.empty() or (lastCellCol < columnNumber)) {
662 char cellAddrBuf[16];
666 else if (lastCellCol - columnNumber < columnNumber) {
667 uint16_t currentCol = lastCellCol;
668 while (not cellNode.empty() and (currentCol > columnNumber)) {
672 if (cellNode.empty() or (currentCol < columnNumber)) {
675 char cellAddrBuf[16];
683 while (currentCol < columnNumber) {
687 if (currentCol > columnNumber) {
689 char cellAddrBuf[16];
697 if (hintColNumber && hintCellNode) {
698 *hintColNumber = columnNumber;
699 *hintCellNode = cellNode;
714 inline int findStringInVector(std::string
const& nodeName, std::vector<std::string_view>
const& nodeOrder)
716 for (
size_t i = 0; i < nodeOrder.size(); ++i)
717 if (nodeName == nodeOrder[i])
return static_cast<int>(i);
732 while (fromNode.type() == pugi::node_pcdata) {
734 toNode.set_value(fromNode.value());
750 std::string
const& nodeName,
751 std::vector<std::string_view>
const& nodeOrder = {},
752 bool force_ns =
false)
754 if (parent.empty())
return XMLNode{};
757 if (nextNode.empty())
769 if (not nextNode.empty()) {
770 if (nextNode.
name() == nodeName)
781 node = parent.
child(nodeName.c_str());
801 attr = node.append_attribute(attrName.c_str());
802 attr.set_value(attrDefaultVal.c_str());
811 if (attr.empty()) attr = node.append_attribute(attrName.c_str());
812 attr.set_value(attrVal.c_str());
826 std::string
const& nodeName,
827 std::string
const& attrName,
828 std::string
const& attrDefaultVal,
829 std::vector<std::string_view>
const& nodeOrder = {})
847 std::string
const& nodeName,
848 std::string
const& attrName,
849 std::string
const& attrVal,
851 std::vector<std::string_view>
const& nodeOrder = {})
855 if (removeAttributes) node.remove_attributes();
871 if (parent.empty())
return false;
873 if (tagNode.empty())
return false;
874 XMLAttribute valAttr = tagNode.attribute(attrName.c_str());
875 if (valAttr.empty()) {
880 return valAttr.as_bool();
890 if (data.size() < 8)
return {0, 0};
893 if (
reinterpret_cast<const uint8_t*
>(data.data())[0] == 0x89 and data.substr(1, 3) ==
"PNG") {
894 if (data.size() < 24)
return {0, 0};
896 const uint8_t* p =
reinterpret_cast<const uint8_t*
>(data.data());
897 uint32_t w = (
static_cast<uint32_t
>(p[16]) << 24) | (
static_cast<uint32_t
>(p[17]) << 16) | (
static_cast<uint32_t
>(p[18]) << 8) |
898 static_cast<uint32_t
>(p[19]);
899 uint32_t h = (
static_cast<uint32_t
>(p[20]) << 24) | (
static_cast<uint32_t
>(p[21]) << 16) | (
static_cast<uint32_t
>(p[22]) << 8) |
900 static_cast<uint32_t
>(p[23]);
905 if (
reinterpret_cast<const uint8_t*
>(data.data())[0] == 0xFF and
reinterpret_cast<const uint8_t*
>(data.data())[1] == 0xD8) {
907 while (offset + 4 < data.size()) {
908 const uint8_t* p =
reinterpret_cast<const uint8_t*
>(data.data()) + offset;
909 if (p[0] != 0xFF)
break;
910 uint8_t marker = p[1];
911 uint32_t length = (
static_cast<uint32_t
>(p[2]) << 8) |
static_cast<uint32_t
>(p[3]);
914 if ((marker >= 0xC0 and marker <= 0xC3) or (marker >= 0xC5 and marker <= 0xC7) or (marker >= 0xC9 and marker <= 0xCB) ||
915 (marker >= 0xCD and marker <= 0xCF))
917 if (offset + 9 > data.size())
return {0, 0};
919 uint32_t h = (
static_cast<uint32_t
>(p[5]) << 8) |
static_cast<uint32_t
>(p[6]);
920 uint32_t w = (
static_cast<uint32_t
>(p[7]) << 8) |
static_cast<uint32_t
>(p[8]);
923 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:193
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:185
void copyLeadingWhitespaces(XMLNode &parent, XMLNode fromNode, XMLNode toNode)
copy all leading pc_data nodes from fromNode to toNode
Definition XLUtilities.hpp:728
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:846
std::string XLContentTypeString(OpenXLSX::XLContentType const &t)
Get a string representation of OpenXLSX::XLContentType.
Definition XLUtilities.hpp:251
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:220
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:152
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:539
constexpr uint16_t MAX_COLS
Definition XLConstants.hpp:8
XMLAttribute appendAndGetAttribute(XMLNode &node, std::string const &attrName, std::string const &attrDefaultVal)
Definition XLUtilities.hpp:796
XLStyleIndex getColumnStyle(XMLNode rowNode, uint16_t colNo)
Definition XLUtilities.hpp:515
int findStringInVector(std::string const &nodeName, std::vector< std::string_view > const &nodeOrder)
Definition XLUtilities.hpp:714
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:327
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:825
constexpr const int SORT_INDEX_NOT_FOUND
find the index of nodeName in nodeOrder
Definition XLUtilities.hpp:713
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:495
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:888
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:807
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:597
void appendEscaped(std::string &out, std::string_view sv)
Fast XML escape: appends escaped characters to out to avoid intermediate allocations.
Definition XLUtilities.hpp:62
XMLNode getRowNode(XMLNode sheetDataNode, uint32_t rowNumber, uint32_t *hintRowNumber=nullptr, XMLNode *hintRowNode=nullptr)
Definition XLUtilities.hpp:407
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:120
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:869
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:749
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:96
constexpr const bool XLKeepAttributes
Definition XLUtilities.hpp:21