1 #ifndef XLNT_DETAIL_SERIALISATION_HELPERS_HPP
2 #define XLNT_DETAIL_SERIALISATION_HELPERS_HPP
3 
4 #include <xlnt/cell/cell_type.hpp>
5 #include <xlnt/cell/index_types.hpp>
6 #include <string>
7 
8 namespace xlnt {
9 namespace detail {
10 
11 /// parsing assumptions used by the following functions
12 /// - on entry, the start element for the element has been consumed by parser->next
13 /// - on exit, the closing element has been consumed by parser->next
14 /// using these assumptions, the following functions DO NOT use parser->peek (SLOW!!!)
15 /// probable further gains from not building an attribute map and using the attribute events instead as the impl just iterates the map
16 
17 /// 'r' == cell reference e.g. 'A1'
18 /// https://docs.microsoft.com/en-us/openspecs/office_standards/ms-oe376/db11a912-b1cb-4dff-b46d-9bedfd10cef0
19 ///
20 /// a lightweight version of xlnt::cell_reference with no extre functionality (absolute/relative, ...)
21 /// many thousands are created during (de)serialisation, so even minor overhead is noticable
22 struct Cell_Reference
23 {
24     // the obvious ctor
Cell_Referencexlnt::detail::Cell_Reference25     explicit Cell_Reference(xlnt::row_t row_arg, xlnt::column_t::index_t column_arg) noexcept
26         : row(row_arg), column(column_arg)
27     {
28     }
29 
30     // the common case. row # is already known during parsing (from parent <row> element)
31     // just need to evaluate the column
Cell_Referencexlnt::detail::Cell_Reference32     explicit Cell_Reference(xlnt::row_t row_arg, const std::string &reference) noexcept
33         : row(row_arg)
34     {
35         // only three characters allowed for the column
36         // assumption:
37         // - regex pattern match: [A-Z]{1,3}\d{1,7}
38         const char *iter = reference.c_str();
39         int temp = *iter - 'A' + 1; // 'A' == 1
40         ++iter;
41         if (*iter >= 'A') // second char
42         {
43             temp *= 26; // LHS values are more significant
44             temp += *iter - 'A' + 1; // 'A' == 1
45             ++iter;
46             if (*iter >= 'A') // third char
47             {
48                 temp *= 26; // LHS values are more significant
49                 temp += *iter - 'A' + 1; // 'A' == 1
50             }
51         }
52         column = static_cast<xlnt::column_t::index_t>(temp);
53     }
54 
55     // for sorting purposes
operator <xlnt::detail::Cell_Reference56     bool operator<(const Cell_Reference &rhs)
57     {
58         // row first, serialisation is done by row then column
59         if (row < rhs.row)
60         {
61             return true;
62         }
63         else if (rhs.row < row)
64         {
65             return false;
66         }
67         // same row, column comparison
68         return column < rhs.column;
69     }
70 
71     xlnt::row_t row; // range:[1, 1048576]
72     xlnt::column_t::index_t column; // range:["A", "ZZZ"] -> [1, 26^3] -> [1, 17576]
73 };
74 
75 // <c> inside <row> element
76 // https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.cell?view=openxml-2.8.1
77 struct Cell
78 {
79     // sort cells by location, row first
operator <xlnt::detail::Cell80     bool operator<(const Cell &rhs)
81     {
82         return ref < rhs.ref;
83     }
84 
85     bool is_phonetic = false; // 'ph'
86     xlnt::cell_type type = xlnt::cell_type::number; // 't'
87     int cell_metatdata_idx = -1; // 'cm'
88     int style_index = -1; // 's'
89     Cell_Reference ref{0, 0}; // 'r'
90     std::string value; // <v> OR <is>
91     std::string formula_string; // <f>
92 };
93 
94 } // namespace detail
95 } // namespace xlnt
96 #endif