Branch data TLA Line data Source code
1 : : // Copyright (c) 2014-2022 Thomas Fussell
2 : : // Copyright (c) 2010-2015 openpyxl
3 : : // Copyright (c) 2024-2025 xlnt-community
4 : : //
5 : : // Permission is hereby granted, free of charge, to any person obtaining a copy
6 : : // of this software and associated documentation files (the "Software"), to deal
7 : : // in the Software without restriction, including without limitation the rights
8 : : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : : // copies of the Software, and to permit persons to whom the Software is
10 : : // furnished to do so, subject to the following conditions:
11 : : //
12 : : // The above copyright notice and this permission notice shall be included in
13 : : // all copies or substantial portions of the Software.
14 : : //
15 : : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : : // THE SOFTWARE
22 : : //
23 : : // @license: http://www.opensource.org/licenses/mit-license.php
24 : : // @author: see AUTHORS file
25 : :
26 : : #include <cctype>
27 : :
28 : : #include <xlnt/cell/cell_reference.hpp>
29 : : #include <xlnt/utils/exceptions.hpp>
30 : : #include <xlnt/worksheet/range_reference.hpp>
31 : :
32 : : #include <detail/constants.hpp>
33 : : #include <detail/serialization/parsers.hpp>
34 : :
35 : : namespace xlnt {
36 : :
37 :CBC 4 : std::size_t cell_reference_hash::operator()(const cell_reference &k) const
38 : : {
39 : 4 : return k.row() * constants::max_column().index + k.column_index();
40 : : }
41 : :
42 : 46 : cell_reference &cell_reference::make_absolute(bool absolute_column, bool absolute_row)
43 : : {
44 : 46 : column_absolute(absolute_column);
45 : 46 : row_absolute(absolute_row);
46 : :
47 : 46 : return *this;
48 : : }
49 : :
50 : 474 : cell_reference::cell_reference()
51 [ + + ]: 474 : : cell_reference(1, 1)
52 : : {
53 : 474 : }
54 : :
55 : 1017 : cell_reference::cell_reference(const std::string &string)
56 : : {
57 : : // If not an error reference, proceed with normal parsing
58 [ + ]: 1017 : auto split = split_reference(string, absolute_column_, absolute_row_);
59 [ + ]: 1010 : column(split.first);
60 : 1010 : row(split.second);
61 : 1010 : }
62 : :
63 : 362 : cell_reference::cell_reference(const char *reference_string)
64 [ + + ]: 365 : : cell_reference(std::string(reference_string))
65 : : {
66 : 359 : }
67 : :
68 : 12952 : cell_reference::cell_reference(column_t column_index, row_t row)
69 : 12952 : : column_(column_index), row_(row)
70 : : {
71 : 25904 : if (row_ == 0
72 [ + + - ]: 12951 : || column_ == 0
73 [ + + - ]: 12951 : || !(row_ <= constants::max_row())
74 [ + + + + : 25903 : || !(column_ <= constants::max_column()))
- + + + ]
75 : : {
76 [ + ]: 1 : throw invalid_cell_reference(column_, row_);
77 : : }
78 : 12951 : }
79 : :
80 : 1 : range_reference cell_reference::operator,(const xlnt::cell_reference &other) const
81 : : {
82 : 1 : return range_reference(*this, other);
83 : : }
84 : :
85 : 1406 : std::string cell_reference::to_string() const
86 : : {
87 : 1406 : std::string string_representation;
88 : :
89 [ + + ]: 1406 : if (absolute_column_)
90 : : {
91 [ + ]: 8 : string_representation.append("$");
92 : : }
93 : :
94 [ + + ]: 1406 : string_representation.append(column_.column_string());
95 : :
96 [ + + ]: 1406 : if (absolute_row_)
97 : : {
98 [ + ]: 8 : string_representation.append("$");
99 : : }
100 : :
101 [ + ]: 1406 : string_representation.append(std::to_string(row_));
102 : :
103 : 1406 : return string_representation;
104 :UBC 0 : }
105 : :
106 : 0 : range_reference cell_reference::to_range() const
107 : : {
108 : 0 : return range_reference(column_, row_, column_, row_);
109 : : }
110 : :
111 :CBC 12 : std::pair<std::string, row_t> cell_reference::split_reference(const std::string &reference_string)
112 : : {
113 : : bool ignore1, ignore2;
114 [ + ]: 16 : return split_reference(reference_string, ignore1, ignore2);
115 : : }
116 : :
117 : 1029 : std::pair<std::string, row_t> cell_reference::split_reference(
118 : : const std::string &reference_string, bool &absolute_column, bool &absolute_row)
119 : : {
120 : 1029 : std::string col_str;
121 : 1029 : std::string row_str;
122 : 1029 : size_t i = 0;
123 : :
124 : : // 1. Check for column absolute reference '$'
125 [ + + + + : 1029 : if (i < reference_string.length() && reference_string[i] == '$')
+ + ]
126 : : {
127 : 10 : absolute_column = true;
128 : 10 : ++i;
129 : : }
130 : : else
131 : : {
132 : 1019 : absolute_column = false;
133 : : }
134 : :
135 : : // 2. Extract all letters as column name
136 [ + + + + : 2090 : while (i < reference_string.length() && std::isalpha(static_cast<unsigned char>(reference_string[i])))
+ + ]
137 : : {
138 [ + ]: 1061 : col_str += static_cast<char>(std::toupper(static_cast<unsigned char>(reference_string[i])));
139 : 1061 : ++i;
140 : : }
141 : :
142 [ + + ]: 1029 : if (col_str.empty())
143 : : {
144 [ + ]: 5 : throw invalid_cell_reference(reference_string);
145 : : }
146 : :
147 : : // 3. Check for row absolute reference '$'
148 [ + + + + : 1024 : if (i < reference_string.length() && reference_string[i] == '$')
+ + ]
149 : : {
150 : 9 : absolute_row = true;
151 : 9 : ++i;
152 : : }
153 : : else
154 : : {
155 : 1015 : absolute_row = false;
156 : : }
157 : :
158 : : // 4. Extract all digits as row number
159 [ + + + + : 2253 : while (i < reference_string.length() && std::isdigit(static_cast<unsigned char>(reference_string[i])))
+ + ]
160 : : {
161 [ + ]: 1229 : row_str += reference_string[i];
162 : 1229 : ++i;
163 : : }
164 : :
165 : : // 5. Validate format: string must be fully parsed and row part cannot be empty
166 [ + + + + : 1024 : if (i != reference_string.length() || row_str.empty())
+ + ]
167 : : {
168 [ + ]: 10 : throw invalid_cell_reference(reference_string);
169 : : }
170 : :
171 : : // 6. Convert row string to number
172 : 1014 : xlnt::row_t row = 0;
173 [ + - + ]: 1014 : if (detail::parse(row_str, row) != std::errc())
174 : : {
175 [ # ]:UBC 0 : throw invalid_cell_reference(reference_string);
176 : : }
177 : :
178 [ + ]:CBC 2028 : return {col_str, row};
179 : 1044 : }
180 : :
181 : 36 : bool cell_reference::column_absolute() const
182 : : {
183 : 36 : return absolute_column_;
184 : : }
185 : :
186 : 46 : void cell_reference::column_absolute(bool absolute_column)
187 : : {
188 : 46 : absolute_column_ = absolute_column;
189 : 46 : }
190 : :
191 : 36 : bool cell_reference::row_absolute() const
192 : : {
193 : 36 : return absolute_row_;
194 : : }
195 : :
196 : 46 : void cell_reference::row_absolute(bool absolute_row)
197 : : {
198 : 46 : absolute_row_ = absolute_row;
199 : 46 : }
200 : :
201 : 33405 : column_t cell_reference::column() const
202 : : {
203 : 33405 : return column_;
204 : : }
205 : :
206 : 1010 : void cell_reference::column(const std::string &column_string)
207 : : {
208 [ + ]: 1010 : column_ = column_t(column_string);
209 : 1010 : }
210 : :
211 : 27544 : column_t::index_t cell_reference::column_index() const
212 : : {
213 : 27544 : return column_.index;
214 : : }
215 : :
216 : 7220 : void cell_reference::column_index(column_t column)
217 : : {
218 : 7220 : column_ = column;
219 : 7220 : }
220 : :
221 : 30247 : row_t cell_reference::row() const
222 : : {
223 : 30247 : return row_;
224 : : }
225 : :
226 : 3154 : void cell_reference::row(row_t row)
227 : : {
228 : 3154 : row_ = row;
229 : 3154 : }
230 : :
231 : 37 : bool cell_reference::operator==(const std::string &reference_string) const
232 : : {
233 [ + + ]: 37 : return *this == cell_reference(reference_string);
234 : : }
235 : :
236 : 35 : bool cell_reference::operator==(const char *reference_string) const
237 : : {
238 [ + + ]: 70 : return *this == std::string(reference_string);
239 : : }
240 : :
241 : 1 : bool cell_reference::operator!=(const cell_reference &comparand) const
242 : : {
243 : 1 : return !(*this == comparand);
244 : : }
245 : :
246 : 1 : bool cell_reference::operator!=(const std::string &reference_string) const
247 : : {
248 [ + + ]: 1 : return *this != cell_reference(reference_string);
249 : : }
250 : :
251 : 1 : bool cell_reference::operator!=(const char *reference_string) const
252 : : {
253 [ + + ]: 2 : return *this != std::string(reference_string);
254 : : }
255 : :
256 : 43 : cell_reference cell_reference::make_offset(int column_offset, int row_offset) const
257 : : {
258 : : // TODO: check for overflow/underflow
259 : 43 : auto relative_column = static_cast<column_t::index_t>(static_cast<int>(column_.index) + column_offset);
260 : 43 : auto relative_row = static_cast<row_t>(static_cast<int>(row_) + row_offset);
261 : :
262 [ + + ]: 43 : return cell_reference(relative_column, relative_row);
263 : : }
264 : :
265 : 9229 : bool cell_reference::operator==(const cell_reference &comparand) const
266 : : {
267 : 9229 : return comparand.column_ == column_
268 [ + + ]: 7795 : && comparand.row_ == row_
269 [ + - ]: 7518 : && absolute_column_ == comparand.absolute_column_
270 [ + + + - ]: 17024 : && absolute_row_ == comparand.absolute_row_;
271 : : }
272 : :
273 : : } // namespace xlnt
|