Branch data TLA Line data Source code
1 : : // Copyright (c) 2014-2022 Thomas Fussell
2 : : // Copyright (c) 2024-2025 xlnt-community
3 : : //
4 : : // Permission is hereby granted, free of charge, to any person obtaining a copy
5 : : // of this software and associated documentation files (the "Software"), to deal
6 : : // in the Software without restriction, including without limitation the rights
7 : : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : : // copies of the Software, and to permit persons to whom the Software is
9 : : // furnished to do so, subject to the following conditions:
10 : : //
11 : : // The above copyright notice and this permission notice shall be included in
12 : : // all copies or substantial portions of the Software.
13 : : //
14 : : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : : // THE SOFTWARE
21 : : //
22 : : // @license: http://www.opensource.org/licenses/mit-license.php
23 : : // @author: see AUTHORS file
24 : :
25 : : #include <xlnt/worksheet/range_reference.hpp>
26 : :
27 : : #include <detail/constants.hpp>
28 : : #include <xlnt/utils/exceptions.hpp>
29 : : #include <detail/serialization/parsers.hpp>
30 : :
31 : : namespace {
32 : :
33 :CBC 131 : bool is_whole_column(const std::string &s)
34 : : {
35 [ + + ]: 131 : if (s.empty())
36 : : {
37 : 1 : return false;
38 : : }
39 : :
40 [ + + ]: 130 : size_t start_pos = (s[0] == '$') ? 1 : 0;
41 [ + + ]: 130 : if (start_pos >= s.length()) // String contains only a "$"
42 : : {
43 : 1 : return false;
44 : : }
45 : :
46 [ + + ]: 246 : for (size_t i = start_pos; i < s.length(); ++i)
47 : : {
48 [ + + ]: 228 : if (!std::isalpha(static_cast<unsigned char>(s[i])))
49 : : {
50 : 111 : return false;
51 : : }
52 : : }
53 : :
54 : 18 : return true;
55 : : }
56 : :
57 : 124 : bool is_whole_row(const std::string &s)
58 : : {
59 [ + + ]: 124 : if (s.empty())
60 : : {
61 : 1 : return false;
62 : : }
63 : :
64 [ + + ]: 123 : size_t start_pos = (s[0] == '$') ? 1 : 0;
65 [ + + ]: 123 : if (start_pos >= s.length()) // String contains only a "$"
66 : : {
67 : 1 : return false;
68 : : }
69 : :
70 [ + + ]: 234 : for (size_t i = start_pos; i < s.length(); ++i)
71 : : {
72 [ + + ]: 212 : if (!std::isdigit(static_cast<unsigned char>(s[i])))
73 : : {
74 : 100 : return false;
75 : : }
76 : : }
77 : :
78 : 22 : return true;
79 : : }
80 : :
81 : 40 : bool extract_absolute (std::string& part)
82 : : {
83 : 40 : bool absolute = part[0] == '$';
84 [ + + ]: 40 : if (absolute)
85 : : {
86 : 14 : part.erase(0, 1);
87 : : }
88 : 40 : return absolute;
89 : : }
90 : : }
91 : :
92 : : namespace xlnt {
93 : :
94 : 5 : range_reference range_reference::make_absolute(const xlnt::range_reference &relative)
95 : : {
96 : 5 : range_reference copy = relative;
97 : :
98 : 5 : copy.top_left_.make_absolute(true, true);
99 : 5 : copy.bottom_right_.make_absolute(true, true);
100 : :
101 : 5 : return copy;
102 : : }
103 : :
104 : 9 : range_reference::range_reference()
105 : 9 : : range_reference("A1")
106 : : {
107 : 9 : }
108 : :
109 : 59 : range_reference::range_reference(const char *range_string)
110 [ + + ]: 65 : : range_reference(std::string(range_string))
111 : : {
112 : 53 : }
113 : :
114 : 233 : range_reference::range_reference(const std::string &range_string)
115 : : {
116 : 233 : auto colon_index = range_string.find(':');
117 : :
118 [ + + ]: 233 : if (colon_index == std::string::npos)
119 : : {
120 : : // Single cell reference, e.g., "A1"
121 [ + ]: 111 : top_left_ = cell_reference(range_string);
122 : 110 : bottom_right_ = top_left_;
123 : 110 : return;
124 : : }
125 : :
126 [ + ]: 122 : std::string start_part = range_string.substr(0, colon_index);
127 [ + ]: 122 : std::string end_part = range_string.substr(colon_index + 1);
128 : :
129 [ + + + - : 122 : if (is_whole_column(start_part) && is_whole_column(end_part))
+ + ]
130 : : {
131 : : // Whole column reference, e.g., "A:C"
132 [ + ]: 9 : bool absoluteStart = extract_absolute(start_part);
133 [ + ]: 9 : bool absoluteEnd = extract_absolute(end_part);
134 : :
135 [ + + + ]: 9 : top_left_ = cell_reference(start_part, 1).make_absolute(absoluteStart, true);
136 [ + + + + ]: 9 : bottom_right_ = cell_reference(end_part, constants::max_row()).make_absolute(absoluteEnd, true);
137 : : }
138 [ + + + - : 113 : else if (is_whole_row(start_part) && is_whole_row(end_part))
+ + ]
139 : : {
140 : : // Whole row reference, e.g., "1:5"
141 [ + ]: 11 : bool absoluteStart = extract_absolute(start_part);
142 [ + ]: 11 : bool absoluteEnd = extract_absolute(end_part);
143 : :
144 : : row_t start_row;
145 [ + + + ]: 11 : if (detail::parse(start_part, start_row) != std::errc())
146 : : {
147 [ + ]: 1 : throw xlnt::invalid_cell_reference(start_part);
148 : : }
149 : : row_t end_row;
150 [ + + + ]: 10 : if (detail::parse(end_part, end_row) != std::errc())
151 : : {
152 [ + ]: 1 : throw xlnt::invalid_cell_reference(end_part);
153 : : }
154 : :
155 [ + + + ]: 9 : top_left_ = cell_reference(constants::min_column(), start_row).make_absolute(true, absoluteStart);
156 [ + + + ]: 9 : bottom_right_ = cell_reference(constants::max_column(), end_row).make_absolute(true, absoluteEnd);
157 : : }
158 : : else
159 : : {
160 [ + ]: 102 : top_left_ = cell_reference(start_part);
161 [ + ]: 99 : bottom_right_ = cell_reference(end_part);
162 : : }
163 : 127 : }
164 : :
165 : 44 : range_reference::range_reference(const cell_reference &top_left,
166 : 44 : const cell_reference &bottom_right)
167 : 44 : : top_left_(top_left),
168 : 44 : bottom_right_(bottom_right)
169 : : {
170 : 44 : }
171 : :
172 : 169 : range_reference::range_reference(column_t column_index_start,
173 : : row_t row_index_start,
174 : : column_t column_index_end,
175 : 169 : row_t row_index_end)
176 : 169 : : top_left_(column_index_start, row_index_start),
177 : 169 : bottom_right_(column_index_end, row_index_end)
178 : : {
179 : 169 : }
180 : :
181 : 2 : range_reference range_reference::make_offset(int column_offset, int row_offset) const
182 : : {
183 [ + ]: 2 : auto top_left = top_left_.make_offset(column_offset, row_offset);
184 [ + ]: 2 : auto bottom_right = bottom_right_.make_offset(column_offset, row_offset);
185 : :
186 : 4 : return range_reference(top_left, bottom_right);
187 : : }
188 : :
189 : 69 : std::size_t range_reference::height() const
190 : : {
191 : 69 : return 1 + bottom_right_.row() - top_left_.row();
192 : : }
193 : :
194 : 101 : std::size_t range_reference::width() const
195 : : {
196 [ + + + ]: 101 : return 1 + (bottom_right_.column() - top_left_.column()).index;
197 : : }
198 : :
199 : 97 : bool range_reference::is_single_cell() const
200 : : {
201 [ + + + + ]: 97 : return width() == 1 && height() == 1;
202 : : }
203 : :
204 : 8 : bool range_reference::whole_row() const
205 : : {
206 [ + + + + : 15 : return top_left_.column() == xlnt::constants::min_column() && top_left_.column_absolute()
+ + ]
207 [ + + + + : 15 : && bottom_right_.column() == xlnt::constants::max_column() && bottom_right_.column_absolute();
+ + + + +
- ]
208 : : }
209 : :
210 : 8 : bool range_reference::whole_column() const
211 : : {
212 [ + + ]: 15 : return top_left_.row() == xlnt::constants::min_row() && top_left_.row_absolute()
213 [ + + + + : 15 : && bottom_right_.row() == xlnt::constants::max_row() && bottom_right_.row_absolute();
+ - ]
214 : : }
215 : :
216 : 94 : std::string range_reference::to_string() const
217 : : {
218 [ + + ]: 94 : if (is_single_cell())
219 [ + ]: 49 : return top_left().to_string();
220 : : else
221 [ + + + + ]: 45 : return top_left_.to_string() + ":" + bottom_right_.to_string();
222 : : }
223 : :
224 : 424 : bool range_reference::operator==(const range_reference &comparand) const
225 : : {
226 [ + + + + ]: 424 : return comparand.top_left_ == top_left_ && comparand.bottom_right_ == bottom_right_;
227 : : }
228 : :
229 : 31 : bool range_reference::operator!=(const range_reference &comparand) const
230 : : {
231 : 31 : return !(*this == comparand);
232 : : }
233 : :
234 : 6212 : cell_reference range_reference::top_left() const
235 : : {
236 : 6212 : return top_left_;
237 : : }
238 : :
239 :UBC 0 : cell_reference range_reference::top_right() const
240 : : {
241 [ # # # ]: 0 : return cell_reference(bottom_right_.column(), top_left_.row());
242 : : }
243 : :
244 : 0 : cell_reference range_reference::bottom_left() const
245 : : {
246 [ # # # ]: 0 : return cell_reference(top_left_.column(), bottom_right_.row());
247 : : }
248 : :
249 :CBC 22206 : cell_reference range_reference::bottom_right() const
250 : : {
251 : 22206 : return bottom_right_;
252 : : }
253 : :
254 : 4 : bool range_reference::contains(const cell_reference &ref) const
255 : : {
256 : 4 : return top_left_.column_index() <= ref.column_index()
257 [ + + ]: 4 : && bottom_right_.column_index() >= ref.column_index()
258 [ + - ]: 3 : && top_left_.row() <= ref.row()
259 [ + - + + ]: 8 : && bottom_right_.row() >= ref.row();
260 : : }
261 : :
262 : 32 : bool range_reference::operator==(const std::string &reference_string) const
263 : : {
264 [ + + ]: 32 : return *this == range_reference(reference_string);
265 : : }
266 : :
267 : 30 : bool range_reference::operator==(const char *reference_string) const
268 : : {
269 [ + + ]: 60 : return *this == std::string(reference_string);
270 : : }
271 : :
272 : 5 : bool range_reference::operator!=(const std::string &reference_string) const
273 : : {
274 [ + + ]: 5 : return *this != range_reference(reference_string);
275 : : }
276 : :
277 : 3 : bool range_reference::operator!=(const char *reference_string) const
278 : : {
279 [ + + ]: 6 : return *this != std::string(reference_string);
280 : : }
281 : :
282 : 1 : bool operator==(const std::string &reference_string, const range_reference &ref)
283 : : {
284 : 1 : return ref == reference_string;
285 : : }
286 : :
287 : 13 : bool operator==(const char *reference_string, const range_reference &ref)
288 : : {
289 : 13 : return ref == reference_string;
290 : : }
291 : :
292 : 1 : bool operator!=(const std::string &reference_string, const range_reference &ref)
293 : : {
294 : 1 : return ref != reference_string;
295 : : }
296 : :
297 : 1 : bool operator!=(const char *reference_string, const range_reference &ref)
298 : : {
299 : 1 : return ref != reference_string;
300 : : }
301 : :
302 : : } // namespace xlnt
|