// Copyright (c) 2014-2016 Thomas Fussell // Copyright (c) 2010-2015 openpyxl // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE // // @license: http://www.opensource.org/licenses/mit-license.php // @author: see AUTHORS file #include #include #include #include #include namespace xlnt { std::size_t cell_reference_hash::operator()(const cell_reference &k) const { return k.get_row() * constants::max_column().index + k.get_column_index().index; } cell_reference &cell_reference::make_absolute(bool absolute_column, bool absolute_row) { column_absolute(absolute_column); row_absolute(absolute_row); return *this; } cell_reference::cell_reference() : cell_reference(1, 1) { } cell_reference::cell_reference(const std::string &string) { auto split = split_reference(string, absolute_column_, absolute_row_); set_column(split.first); set_row(split.second); } cell_reference::cell_reference(const char *reference_string) : cell_reference(std::string(reference_string)) { } cell_reference::cell_reference(const std::string &column, row_t row) : cell_reference(column_t(column), row) { } cell_reference::cell_reference(column_t column_index, row_t row) : column_(column_index), row_(row), absolute_row_(false), absolute_column_(false) { if (row_ == 0 || column_ == 0) { throw value_error(); } if (!(row_ <= constants::max_row()) || !(column_ <= constants::max_column())) { throw cell_coordinates_error(column_, row_); } } range_reference cell_reference::operator, (const xlnt::cell_reference &other) const { return range_reference(*this, other); } std::string cell_reference::to_string() const { std::string string_representation; if (absolute_column_) { string_representation.append("$"); } string_representation.append(column_.column_string()); if (absolute_row_) { string_representation.append("$"); } string_representation.append(std::to_string(row_)); return string_representation; } range_reference cell_reference::to_range() const { return range_reference(column_, row_, column_, row_); } std::pair cell_reference::split_reference(const std::string &reference_string, bool &absolute_column, bool &absolute_row) { absolute_column = false; absolute_row = false; // Convert a coordinate string like 'B12' to a tuple ('B', 12) bool column_part = true; std::string column_string; for (auto character : reference_string) { char upper = std::toupper(character, std::locale::classic()); if (std::isalpha(character, std::locale::classic())) { if (column_part) { column_string.append(1, upper); } else { throw cell_coordinates_error(reference_string); } } else if (character == '$') { if (column_part) { if (column_string.empty()) { column_string.append(1, upper); } else { column_part = false; } } } else { if (column_part) { column_part = false; } else if (!std::isdigit(character, std::locale::classic())) { throw cell_coordinates_error(reference_string); } } } std::string row_string = reference_string.substr(column_string.length()); if (row_string.length() == 0) { throw cell_coordinates_error(reference_string); } if (column_string[0] == '$') { absolute_row = true; column_string = column_string.substr(1); } if (row_string[0] == '$') { absolute_column = true; row_string = row_string.substr(1); } return { column_string, std::stoi(row_string) }; } bool cell_reference::column_absolute() const { return absolute_column_; } void cell_reference::column_absolute(bool absolute_column) { absolute_column_ = absolute_column; } bool cell_reference::row_absolute() const { return absolute_row_; } void cell_reference::row_absolute(bool absolute_row) { absolute_row_ = absolute_row; } column_t cell_reference::get_column() const { return column_; } void cell_reference::set_column(const std::string &column_string) { column_ = column_t(column_string); } column_t cell_reference::get_column_index() const { return column_; } void cell_reference::set_column_index(column_t column) { column_ = column; } row_t cell_reference::get_row() const { return row_; } void cell_reference::set_row(row_t row) { row_ = row; } bool cell_reference::operator==(const std::string &reference_string) const { return *this == cell_reference(reference_string); } bool cell_reference::operator==(const char *reference_string) const { return *this == std::string(reference_string); } bool cell_reference::operator!=(const cell_reference &comparand) const { return !(*this == comparand); } bool cell_reference::operator!=(const std::string &reference_string) const { return *this != cell_reference(reference_string); } bool cell_reference::operator!=(const char *reference_string) const { return *this != std::string(reference_string); } cell_reference cell_reference::make_offset(int column_offset, int row_offset) const { //TODO: check for overflow/underflow return cell_reference(static_cast(static_cast(column_.index) + column_offset), static_cast(static_cast(row_) + row_offset)); } bool cell_reference::operator==(const cell_reference &comparand) const { return comparand.column_ == column_ && comparand.row_ == row_ && absolute_column_ == comparand.absolute_column_ && absolute_row_ == comparand.absolute_row_; } bool cell_reference::operator<(const cell_reference &other) { if (row_ != other.row_) { return row_ < other.row_; } return column_ < other.column_; } bool cell_reference::operator>(const cell_reference &other) { if (row_ != other.row_) { return row_ > other.row_; } return column_ > other.column_; } bool cell_reference::operator<=(const cell_reference &other) { if (row_ != other.row_) { return row_ < other.row_; } return column_ <= other.column_; } bool cell_reference::operator>=(const cell_reference &other) { if (row_ != other.row_) { return row_ > other.row_; } return column_ >= other.column_; } } // namespace xlnt