diff --git a/include/xlnt/cell/cell.hpp b/include/xlnt/cell/cell.hpp index ebe37f8d..18161adb 100644 --- a/include/xlnt/cell/cell.hpp +++ b/include/xlnt/cell/cell.hpp @@ -139,7 +139,7 @@ public: cell &operator=(const time &value); cell &operator=(const datetime &value); - bool operator==(const cell &comparand) const { return d_ == comparand.d_; } + bool operator==(const cell &comparand) const; bool operator==(std::nullptr_t) const; bool operator==(bool comparand) const; bool operator==(int comparand) const; diff --git a/include/xlnt/common/datetime.hpp b/include/xlnt/common/datetime.hpp index 9c866fe0..41b0943c 100644 --- a/include/xlnt/common/datetime.hpp +++ b/include/xlnt/common/datetime.hpp @@ -29,14 +29,14 @@ namespace xlnt { struct date { static date today(); - static date from_number(long double number, int base_year = 1900); + static date from_number(int days_since_base_year, int base_year = 1900); date(int year, int month, int day) : year(year), month(month), day(day) { } - double to_number(int base_year = 1900) const; + int to_number(int base_year = 1900) const; bool operator==(const date &comparand) const; int year; @@ -47,7 +47,7 @@ struct date struct time { static time now(); - static time from_number(long double number, int base_year = 1900); + static time from_number(long double number); time(int hour = 0, int minute = 0, int second = 0, int microsecond = 0) : hour(hour), minute(minute), second(second), microsecond(microsecond) @@ -55,7 +55,7 @@ struct time } explicit time(const std::string &time_string); - double to_number(int base_year = 1900) const; + double to_number() const; bool operator==(const time &comparand) const; int hour; diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index 79a6f992..91987eb8 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -23,6 +23,7 @@ // @author: see AUTHORS file #pragma once +#include #include #include #include @@ -161,7 +162,7 @@ public: private: friend class worksheet; bool get_already_saved() const; - detail::workbook_impl *d_; + std::unique_ptr d_; }; } // namespace xlnt diff --git a/source/cell.cpp b/source/cell.cpp index 0bae518a..e62d0cbb 100644 --- a/source/cell.cpp +++ b/source/cell.cpp @@ -287,8 +287,7 @@ bool cell::operator==(const time &comparand) const return false; } - auto base_year = worksheet(d_->parent_).get_parent().get_base_year(); - return time::from_number(d_->numeric_value, base_year) == comparand; + return time::from_number(d_->numeric_value) == comparand; } bool cell::operator==(const date &comparand) const @@ -299,7 +298,7 @@ bool cell::operator==(const date &comparand) const } auto base_year = worksheet(d_->parent_).get_parent().get_base_year(); - return date::from_number(d_->numeric_value, base_year) == comparand; + return date::from_number((int)d_->numeric_value, base_year) == comparand; } bool cell::operator==(const datetime &comparand) const @@ -313,6 +312,43 @@ bool cell::operator==(const datetime &comparand) const return datetime::from_number(d_->numeric_value, base_year) == comparand; } +bool cell::operator==(const cell &comparand) const +{ + if(comparand == nullptr) + { + return d_ == nullptr; + } + + if(comparand.get_data_type() != get_data_type()) + { + return false; + } + + switch(get_data_type()) + { + case type::boolean: + return d_->numeric_value == comparand.d_->numeric_value; + case type::error: + return d_->string_value == comparand.d_->string_value; + case type::string: + return d_->string_value == comparand.d_->string_value; + case type::formula: + return d_->string_value == comparand.d_->string_value; + case type::null: + return true; + case type::numeric: + if(is_date() && comparand.is_date()) + { + auto base_year = worksheet(d_->parent_).get_parent().get_base_year(); + auto other_base_year = worksheet(comparand.d_->parent_).get_parent().get_base_year(); + return date::from_number((int)d_->numeric_value, base_year) == date::from_number((int)comparand.d_->numeric_value, other_base_year); + } + return d_->numeric_value == comparand.d_->numeric_value; + } + + return false; +} + bool operator==(int comparand, const xlnt::cell &cell) { return cell == comparand; @@ -481,7 +517,8 @@ cell &cell::operator=(const time &value) cell &cell::operator=(const date &value) { d_->type_ = type::numeric; - d_->numeric_value = value.to_number(); + auto base_year = worksheet(d_->parent_).get_parent().get_base_year(); + d_->numeric_value = value.to_number(base_year); d_->is_date_ = true; return *this; } @@ -489,7 +526,8 @@ cell &cell::operator=(const date &value) cell &cell::operator=(const datetime &value) { d_->type_ = type::numeric; - d_->numeric_value = value.to_number(); + auto base_year = worksheet(d_->parent_).get_parent().get_base_year(); + d_->numeric_value = value.to_number(base_year); d_->is_date_ = true; return *this; } diff --git a/source/datetime.cpp b/source/datetime.cpp index c9856437..536bae3a 100644 --- a/source/datetime.cpp +++ b/source/datetime.cpp @@ -5,7 +5,7 @@ namespace xlnt { -time time::from_number(long double raw_time, int base_year) +time time::from_number(long double raw_time) { double integer_part; double fractional_part = std::modf((double)raw_time, &integer_part); @@ -35,49 +35,45 @@ time time::from_number(long double raw_time, int base_year) return time(hour, minute, second, microsecond); } -date date::from_number(long double number, int base_year) +date date::from_number(int days_since_base_year, int base_year) { - int year = (int)number / 365; - number -= year * 365; - int month = (int)number / 30; - number -= month * 30; - int day = (int)number; - return date(year + base_year, month, day + 1); + date result(0, 0, 0); + + if(base_year == 1904) + { + days_since_base_year += 1462; + } + + if(days_since_base_year == 60) + { + result.day = 29; + result.month = 2; + result.year = 1900; + } + else if(days_since_base_year < 60) + { + days_since_base_year++; + } + + int l = days_since_base_year + 68569 + 2415019; + int n = int((4 * l) / 146097); + l = l - int((146097 * n + 3) / 4); + int i = int((4000 * (l + 1)) / 1461001); + l = l - int((1461 * i) / 4) + 31; + int j = int((80 * l) / 2447); + result.day = l - int((2447 * j) / 80); + l = int(j / 11); + result.month = j + 2 - (12 * l); + result.year = 100 * (n - 49) + i + l; + + return result; } datetime datetime::from_number(long double raw_time, int base_year) { - double integer_part; - double fractional_part = std::modf((double)raw_time, &integer_part); - fractional_part *= 24; - int hour = (int)fractional_part; - fractional_part = 60 * (fractional_part - hour); - int minute = (int)fractional_part; - fractional_part = 60 * (fractional_part - minute); - int second = (int)fractional_part; - fractional_part = 1000000 * (fractional_part - second); - int microsecond = (int)fractional_part; - if(microsecond == 999999 && fractional_part - microsecond > 0.5) - { - microsecond = 0; - second += 1; - if(second == 60) - { - second = 0; - minute += 1; - if(minute == 60) - { - minute = 0; - hour += 1; - } - } - } - int year = (int)integer_part / 365; - integer_part -= year * 365; - int month = (int)integer_part / 30; - integer_part -= month * 30; - int day = (int)integer_part; - return datetime(year + base_year, month, day + 1, hour, minute, second, microsecond); + auto date_part = date::from_number((int)raw_time, base_year); + auto time_part = time::from_number(raw_time); + return datetime(date_part.year, date_part.month, date_part.day, time_part.hour, time_part.minute, time_part.second, time_part.microsecond); } bool date::operator==(const date &comparand) const @@ -122,7 +118,7 @@ time::time(const std::string &time_string) : hour(0), minute(0), second(0), micr } } -double time::to_number(int base_year) const +double time::to_number() const { double number = microsecond; number /= 1000000; @@ -135,38 +131,49 @@ double time::to_number(int base_year) const return number; } -double date::to_number(int base_year) const +int date::to_number(int base_year) const { - double number = (day - 1) + month * 30 + (year - base_year) * 365; - return number; + if(day == 29 && month == 2 && year == 1900) + { + return 60; + } + + int days_since_1900 = int((1461 * (year + 4800 + int((month - 14) / 12))) / 4) + + int((367 * (month - 2 - 12 * ((month - 14) / 12))) / 12) + - int((3 * (int((year + 4900 + int((month - 14) / 12)) / 100))) / 4) + + day - 2415019 - 32075; + + if(days_since_1900 <= 60) + { + days_since_1900--; + } + + if(base_year == 1904) + { + return days_since_1900 - 1461; + } + + return days_since_1900; } double datetime::to_number(int base_year) const { - double number = microsecond; - number /= 1000000; - number += second; - number /= 60; - number += minute; - number /= 60; - number += hour; - number /= 24; - number += (day - 1) + month * 30 + (year - base_year) * 365; - return number; + return date(year, month, day).to_number(base_year) + + time(hour, minute, second, microsecond).to_number(); } date date::today() { std::time_t raw_time = std::time(0); std::tm now = *std::localtime(&raw_time); - return date(now.tm_year, now.tm_mon + 1, now.tm_mday); + return date(1900 + now.tm_year, now.tm_mon + 1, now.tm_mday); } datetime datetime::now() { std::time_t raw_time = std::time(0); std::tm now = *std::localtime(&raw_time); - return datetime(now.tm_year, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec); + return datetime(1900 + now.tm_year, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec); } } // namespace xlnt diff --git a/source/detail/workbook_impl.hpp b/source/detail/workbook_impl.hpp index 3759f15e..16035a2c 100644 --- a/source/detail/workbook_impl.hpp +++ b/source/detail/workbook_impl.hpp @@ -8,6 +8,8 @@ namespace detail { struct workbook_impl { workbook_impl(optimization o); + workbook_impl &operator=(const workbook_impl &) = delete; + workbook_impl(const workbook_impl &) = delete; bool already_saved_; bool optimized_read_; bool optimized_write_; diff --git a/source/detail/worksheet_impl.hpp b/source/detail/worksheet_impl.hpp index db16b455..2d76464e 100644 --- a/source/detail/worksheet_impl.hpp +++ b/source/detail/worksheet_impl.hpp @@ -34,6 +34,13 @@ struct worksheet_impl title_ = other.title_; freeze_panes_ = other.freeze_panes_; cell_map_ = other.cell_map_; + for(auto &row : cell_map_) + { + for(auto &cell : row.second) + { + cell.second.parent_ = this; + } + } relationships_ = other.relationships_; page_setup_ = other.page_setup_; auto_filter_ = other.auto_filter_; diff --git a/source/workbook.cpp b/source/workbook.cpp index df91308b..c8cb603a 100644 --- a/source/workbook.cpp +++ b/source/workbook.cpp @@ -188,10 +188,8 @@ worksheet workbook::create_sheet() title = "Sheet" + std::to_string(++index); } - d_->worksheets_.emplace_back(this, title); - worksheet ws(&d_->worksheets_.back()); - - return ws; + d_->worksheets_.push_back(detail::worksheet_impl(this, title)); + return worksheet(&d_->worksheets_.back()); } void workbook::add_sheet(xlnt::worksheet worksheet) @@ -551,7 +549,7 @@ bool workbook::save(const std::string &filename) bool workbook::operator==(const workbook &rhs) const { - return d_ == rhs.d_; + return d_.get() == rhs.d_.get(); } } diff --git a/tests/runner-autogen.cpp b/tests/runner-autogen.cpp index 42daaaa2..6ea03b74 100644 --- a/tests/runner-autogen.cpp +++ b/tests/runner-autogen.cpp @@ -21,7 +21,7 @@ int main( int argc, char *argv[] ) { return status; } bool suite_test_cell_init = false; -#include "/Users/thomas/Development/xlnt/tests/test_cell.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_cell.hpp" static test_cell suite_test_cell; @@ -238,7 +238,7 @@ public: void runTest() { suite_test_cell.test_is_not_date_color_format(); } } testDescription_suite_test_cell_test_is_not_date_color_format; -#include "/Users/thomas/Development/xlnt/tests/test_chart.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_chart.hpp" static test_chart suite_test_chart; @@ -329,7 +329,7 @@ public: void runTest() { suite_test_chart.test_write_chart_scatter(); } } testDescription_suite_test_chart_test_write_chart_scatter; -#include "/Users/thomas/Development/xlnt/tests/test_dump.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_dump.hpp" static test_dump suite_test_dump; @@ -366,7 +366,7 @@ public: void runTest() { suite_test_dump.test_append_after_save(); } } testDescription_suite_test_dump_test_append_after_save; -#include "/Users/thomas/Development/xlnt/tests/test_named_range.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_named_range.hpp" static test_named_range suite_test_named_range; @@ -457,7 +457,7 @@ public: void runTest() { suite_test_named_range.test_can_be_saved(); } } testDescription_suite_test_named_range_test_can_be_saved; -#include "/Users/thomas/Development/xlnt/tests/test_number_format.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_number_format.hpp" static test_number_format suite_test_number_format; @@ -560,7 +560,7 @@ public: void runTest() { suite_test_number_format.test_mac_date(); } } testDescription_suite_test_number_format_test_mac_date; -#include "/Users/thomas/Development/xlnt/tests/test_props.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_props.hpp" static test_props suite_test_props; @@ -603,7 +603,7 @@ public: void runTest() { suite_test_props.test_write_properties_app(); } } testDescription_suite_test_props_test_write_properties_app; -#include "/Users/thomas/Development/xlnt/tests/test_read.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_read.hpp" static test_read suite_test_read; @@ -736,7 +736,7 @@ public: void runTest() { suite_test_read.test_read_date_value(); } } testDescription_suite_test_read_test_read_date_value; -#include "/Users/thomas/Development/xlnt/tests/test_strings.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_strings.hpp" static test_strings suite_test_strings; @@ -767,7 +767,7 @@ public: void runTest() { suite_test_strings.test_formatted_string_table(); } } testDescription_suite_test_strings_test_formatted_string_table; -#include "/Users/thomas/Development/xlnt/tests/test_style.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_style.hpp" static test_style suite_test_style; @@ -864,7 +864,7 @@ public: void runTest() { suite_test_style.test_read_cell_style(); } } testDescription_suite_test_style_test_read_cell_style; -#include "/Users/thomas/Development/xlnt/tests/test_theme.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_theme.hpp" static test_theme suite_test_theme; @@ -877,7 +877,7 @@ public: void runTest() { suite_test_theme.test_write_theme(); } } testDescription_suite_test_theme_test_write_theme; -#include "/Users/thomas/Development/xlnt/tests/test_workbook.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_workbook.hpp" static test_workbook suite_test_workbook; @@ -1004,7 +1004,7 @@ public: void runTest() { suite_test_workbook.test_write_regular_float(); } } testDescription_suite_test_workbook_test_write_regular_float; -#include "/Users/thomas/Development/xlnt/tests/test_worksheet.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_worksheet.hpp" static test_worksheet suite_test_worksheet; @@ -1173,7 +1173,7 @@ public: void runTest() { suite_test_worksheet.test_printer_settings(); } } testDescription_suite_test_worksheet_test_printer_settings; -#include "/Users/thomas/Development/xlnt/tests/test_write.hpp" +#include "C:\Users\taf656\Development\xlnt\tests\test_write.hpp" static test_write suite_test_write; diff --git a/tests/test_dump.hpp b/tests/test_dump.hpp index 0226256a..f936f756 100644 --- a/tests/test_dump.hpp +++ b/tests/test_dump.hpp @@ -57,7 +57,7 @@ public: std::vector current_row; for(std::size_t x = 0; x < letters.size(); x++) { - current_row.push_back(xlnt::date(2010 + x, 5, row + 1)); + current_row.push_back(xlnt::date(2010 + (int)x, 5, row + 1)); } ws.append(current_row); } diff --git a/tests/test_read.hpp b/tests/test_read.hpp index 11082527..ee5e55a7 100644 --- a/tests/test_read.hpp +++ b/tests/test_read.hpp @@ -160,7 +160,6 @@ public: void test_read_date_value() { - TS_SKIP("something bad is happening here..."); //auto path = PathHelper::GetDataDirectory() + "/genuine/empty-with-styles.xlsx"; //wb_with_styles.load(path); //worksheet_with_styles = wb_with_styles.get_sheet_by_name("Sheet1");