diff --git a/include/xlnt/cell/cell.hpp b/include/xlnt/cell/cell.hpp index 089c157d..fddd1ab7 100644 --- a/include/xlnt/cell/cell.hpp +++ b/include/xlnt/cell/cell.hpp @@ -29,7 +29,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { @@ -412,7 +412,7 @@ private: /// inline std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell) { - return stream << cell.to_string(); + return stream << std::string(cell.to_string().data()); } } // namespace xlnt diff --git a/include/xlnt/cell/cell_reference.hpp b/include/xlnt/cell/cell_reference.hpp index e4e35793..f15b1e4a 100644 --- a/include/xlnt/cell/cell_reference.hpp +++ b/include/xlnt/cell/cell_reference.hpp @@ -28,7 +28,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/cell/comment.hpp b/include/xlnt/cell/comment.hpp index b141ede7..025ba97d 100644 --- a/include/xlnt/cell/comment.hpp +++ b/include/xlnt/cell/comment.hpp @@ -2,7 +2,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/cell/types.hpp b/include/xlnt/cell/types.hpp index e88d20b8..39d55642 100644 --- a/include/xlnt/cell/types.hpp +++ b/include/xlnt/cell/types.hpp @@ -27,7 +27,7 @@ #include -#include "xlnt_config.hpp" +#include // We might want to change these types for various optimizations in the future // so use typedefs. diff --git a/include/xlnt/drawing/drawing.hpp b/include/xlnt/drawing/drawing.hpp index b2453c96..ee4a64d1 100644 --- a/include/xlnt/drawing/drawing.hpp +++ b/include/xlnt/drawing/drawing.hpp @@ -23,7 +23,7 @@ // @author: see AUTHORS file #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/formula/tokenizer.hpp b/include/xlnt/formula/tokenizer.hpp index d064246c..f28c0fa9 100644 --- a/include/xlnt/formula/tokenizer.hpp +++ b/include/xlnt/formula/tokenizer.hpp @@ -1,6 +1,6 @@ #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/formula/translator.hpp b/include/xlnt/formula/translator.hpp index 6fbc3932..00287814 100644 --- a/include/xlnt/formula/translator.hpp +++ b/include/xlnt/formula/translator.hpp @@ -3,7 +3,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/packaging/document_properties.hpp b/include/xlnt/packaging/document_properties.hpp index d12a8002..840e1473 100644 --- a/include/xlnt/packaging/document_properties.hpp +++ b/include/xlnt/packaging/document_properties.hpp @@ -27,7 +27,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/packaging/manifest.hpp b/include/xlnt/packaging/manifest.hpp index 6acc4093..1c58ce6f 100644 --- a/include/xlnt/packaging/manifest.hpp +++ b/include/xlnt/packaging/manifest.hpp @@ -4,7 +4,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/packaging/zip_file.hpp b/include/xlnt/packaging/zip_file.hpp index 21669d90..441b314b 100644 --- a/include/xlnt/packaging/zip_file.hpp +++ b/include/xlnt/packaging/zip_file.hpp @@ -8,7 +8,7 @@ #include -#include "xlnt_config.hpp" +#include // Note: this comes from https://github.com/tfussell/miniz-cpp diff --git a/include/xlnt/serialization/comment_serializer.hpp b/include/xlnt/serialization/comment_serializer.hpp index 41367007..83261103 100644 --- a/include/xlnt/serialization/comment_serializer.hpp +++ b/include/xlnt/serialization/comment_serializer.hpp @@ -28,7 +28,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/serialization/encoding.hpp b/include/xlnt/serialization/encoding.hpp index 62053729..96191d32 100644 --- a/include/xlnt/serialization/encoding.hpp +++ b/include/xlnt/serialization/encoding.hpp @@ -1,6 +1,6 @@ #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/serialization/excel_serializer.hpp b/include/xlnt/serialization/excel_serializer.hpp index 370103f8..892ef717 100644 --- a/include/xlnt/serialization/excel_serializer.hpp +++ b/include/xlnt/serialization/excel_serializer.hpp @@ -30,7 +30,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/serialization/manifest_serializer.hpp b/include/xlnt/serialization/manifest_serializer.hpp index 7441b4b7..1377b5b8 100644 --- a/include/xlnt/serialization/manifest_serializer.hpp +++ b/include/xlnt/serialization/manifest_serializer.hpp @@ -2,7 +2,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/serialization/relationship_serializer.hpp b/include/xlnt/serialization/relationship_serializer.hpp index 226526a0..08559c99 100644 --- a/include/xlnt/serialization/relationship_serializer.hpp +++ b/include/xlnt/serialization/relationship_serializer.hpp @@ -4,7 +4,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/serialization/shared_strings_serializer.hpp b/include/xlnt/serialization/shared_strings_serializer.hpp index e80dd855..81456f01 100644 --- a/include/xlnt/serialization/shared_strings_serializer.hpp +++ b/include/xlnt/serialization/shared_strings_serializer.hpp @@ -27,7 +27,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/serialization/style_serializer.hpp b/include/xlnt/serialization/style_serializer.hpp index 79ccb4c0..fdf1bbac 100644 --- a/include/xlnt/serialization/style_serializer.hpp +++ b/include/xlnt/serialization/style_serializer.hpp @@ -29,7 +29,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/serialization/theme_serializer.hpp b/include/xlnt/serialization/theme_serializer.hpp index 53118823..3b4d1366 100644 --- a/include/xlnt/serialization/theme_serializer.hpp +++ b/include/xlnt/serialization/theme_serializer.hpp @@ -25,7 +25,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/serialization/workbook_serializer.hpp b/include/xlnt/serialization/workbook_serializer.hpp index ecdfaf19..a4b41fa7 100644 --- a/include/xlnt/serialization/workbook_serializer.hpp +++ b/include/xlnt/serialization/workbook_serializer.hpp @@ -26,7 +26,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/serialization/worksheet_serializer.hpp b/include/xlnt/serialization/worksheet_serializer.hpp index 35d008a5..61082267 100644 --- a/include/xlnt/serialization/worksheet_serializer.hpp +++ b/include/xlnt/serialization/worksheet_serializer.hpp @@ -28,7 +28,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/serialization/xml_document.hpp b/include/xlnt/serialization/xml_document.hpp index 4b7f3d7f..3c1e303a 100644 --- a/include/xlnt/serialization/xml_document.hpp +++ b/include/xlnt/serialization/xml_document.hpp @@ -5,7 +5,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { namespace detail { struct xml_document_impl; } diff --git a/include/xlnt/serialization/xml_node.hpp b/include/xlnt/serialization/xml_node.hpp index 7a674ab2..3bbbee26 100644 --- a/include/xlnt/serialization/xml_node.hpp +++ b/include/xlnt/serialization/xml_node.hpp @@ -5,7 +5,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { namespace detail { struct xml_node_impl; } diff --git a/include/xlnt/serialization/xml_serializer.hpp b/include/xlnt/serialization/xml_serializer.hpp index 2bf268e3..f281b3d5 100644 --- a/include/xlnt/serialization/xml_serializer.hpp +++ b/include/xlnt/serialization/xml_serializer.hpp @@ -2,7 +2,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/styles/alignment.hpp b/include/xlnt/styles/alignment.hpp index 51f3f4d9..7b8c9bb1 100644 --- a/include/xlnt/styles/alignment.hpp +++ b/include/xlnt/styles/alignment.hpp @@ -25,7 +25,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/styles/border.hpp b/include/xlnt/styles/border.hpp index 233e2715..338f579f 100644 --- a/include/xlnt/styles/border.hpp +++ b/include/xlnt/styles/border.hpp @@ -29,7 +29,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/styles/color.hpp b/include/xlnt/styles/color.hpp index a51fb095..4beded0f 100644 --- a/include/xlnt/styles/color.hpp +++ b/include/xlnt/styles/color.hpp @@ -26,7 +26,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/styles/fill.hpp b/include/xlnt/styles/fill.hpp index 8b614a2d..6ae54b63 100644 --- a/include/xlnt/styles/fill.hpp +++ b/include/xlnt/styles/fill.hpp @@ -26,7 +26,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/styles/font.hpp b/include/xlnt/styles/font.hpp index cfb20edc..939a81a1 100644 --- a/include/xlnt/styles/font.hpp +++ b/include/xlnt/styles/font.hpp @@ -28,7 +28,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/styles/named_style.hpp b/include/xlnt/styles/named_style.hpp index 126e642c..8cc8fee7 100644 --- a/include/xlnt/styles/named_style.hpp +++ b/include/xlnt/styles/named_style.hpp @@ -25,7 +25,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/styles/number_format.hpp b/include/xlnt/styles/number_format.hpp index ffe1ceb3..e1193e48 100644 --- a/include/xlnt/styles/number_format.hpp +++ b/include/xlnt/styles/number_format.hpp @@ -28,7 +28,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/styles/protection.hpp b/include/xlnt/styles/protection.hpp index 007b8d08..b0915265 100644 --- a/include/xlnt/styles/protection.hpp +++ b/include/xlnt/styles/protection.hpp @@ -27,7 +27,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/styles/side.hpp b/include/xlnt/styles/side.hpp index 63cd8ee7..5a3c5437 100644 --- a/include/xlnt/styles/side.hpp +++ b/include/xlnt/styles/side.hpp @@ -27,7 +27,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/styles/style.hpp b/include/xlnt/styles/style.hpp index f2e43868..cf69e8ee 100644 --- a/include/xlnt/styles/style.hpp +++ b/include/xlnt/styles/style.hpp @@ -30,7 +30,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/utils/datetime.hpp b/include/xlnt/utils/datetime.hpp index 9aa38804..3cd0b032 100644 --- a/include/xlnt/utils/datetime.hpp +++ b/include/xlnt/utils/datetime.hpp @@ -24,7 +24,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/utils/exceptions.hpp b/include/xlnt/utils/exceptions.hpp index 285da1f4..48663e7f 100644 --- a/include/xlnt/utils/exceptions.hpp +++ b/include/xlnt/utils/exceptions.hpp @@ -27,7 +27,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { @@ -48,7 +48,7 @@ class XLNT_CLASS cell_coordinates_exception class XLNT_CLASS illegal_character_error { public: - illegal_character_error(char c); + illegal_character_error(utf32_char c); }; /// diff --git a/include/xlnt/utils/hash_combine.hpp b/include/xlnt/utils/hash_combine.hpp index ce7579a7..077d1641 100644 --- a/include/xlnt/utils/hash_combine.hpp +++ b/include/xlnt/utils/hash_combine.hpp @@ -2,7 +2,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/utils/string.hpp b/include/xlnt/utils/string.hpp index 2ea8ae63..644b86cf 100644 --- a/include/xlnt/utils/string.hpp +++ b/include/xlnt/utils/string.hpp @@ -1,139 +1,87 @@ #pragma once -#include #include #include -#include -#include +#include #include -#include "xlnt_config.hpp" +#ifdef XLNT_STD_STRING +#include +#endif + +#include namespace xlnt { +template +class iter_range +{ +public: + iter_range(T begin_iter, T end_iter) : begin_(begin_iter), end_(end_iter) + { + } + + T begin() { return begin_; } + T end() { return end_; } + +private: + T begin_; + T end_; +}; + +using utf_mb_narrow_char = char; +using utf_mb_narrow_string = utf_mb_narrow_char[]; +using utf_mb_wide_char = wchar_t; +using utf_mb_wide_string = utf_mb_wide_char[]; +using utf8_char = char; +using utf8_string = utf8_char[]; +using utf16_char = char16_t; +using utf16_string = utf16_char[]; +using utf32_char = char32_t; +using utf32_string = utf32_char[]; + class XLNT_CLASS string { public: - using value_type = std::uint32_t; - using reference = value_type &; - using const_reference = value_type &; - using pointer = value_type *; - using const_pointer = const pointer; - using byte = char; + using code_point = utf32_char; + using reference = code_point &; + using const_reference = const code_point &; + using pointer = code_point *; + using const_pointer = const code_point *; + using byte = char; using byte_pointer = byte *; using const_byte_pointer = const byte *; using difference_type = std::ptrdiff_t; using size_type = std::size_t; - - using utf_mb_narrow_char = char; - using utf_mb_narrow_string = utf_mb_narrow_char[]; - using utf_mb_wide_char = wchar_t; - using utf_mb_wide_string = utf_mb_wide_char[]; - using utf8_char = char; - using utf8_string = utf8_char[]; - using utf16_char = char16_t; - using utf16_string = utf16_char[]; - using utf32_char = char32_t; - using utf32_string = utf32_char[]; - - class code_point + + class const_iterator; + + class iterator : public std::iterator { public: - code_point(byte_pointer data, size_type index, size_type end) - : data_(data), - index_(index), - end_(end) - { - } + iterator(string *parent, size_type index); + + iterator(const iterator &other); + + code_point operator*(); + + bool operator==(const iterator &other) const; + + bool operator!=(const iterator &other) const { return !(*this == other); } - code_point(const_byte_pointer data, size_type index, size_type end) - : data_(const_cast(data)), - index_(index), - end_(end) - { - } + difference_type operator-(const iterator &other) const; + + iterator &operator+=(int offset) { return *this = *this + offset; } + + iterator &operator-=(int offset) { return *this = *this - offset; } - code_point &operator=(utf32_char value); + iterator operator+(int offset); + + iterator operator-(int offset) { return *this + (-1 * offset); } - code_point &operator=(const code_point &value) - { - return *this = value.get(); - } + iterator &operator--(); - bool operator==(char rhs) const; - bool operator!=(char rhs) const; - bool operator<(char rhs) const; - bool operator<=(char rhs) const; - bool operator>(char rhs) const; - bool operator>=(char rhs) const; - - utf32_char get() const; - - byte_pointer data_; - size_type index_; - size_type end_; - }; - - template - class common_iterator : public std::iterator - { - public: - common_iterator(byte_pointer data, size_type index, size_type length) - : current_(data, index, length) - { - } - - common_iterator(const_byte_pointer data, size_type index, size_type length) - : current_(data, index, length) - { - } - - common_iterator(const common_iterator &other) - : current_(other.current_) - { - } - - common_iterator(const common_iterator &other) - : current_(other.current_) - { - } - - code_point &operator*() - { - return current_; - } - - bool operator==(const common_iterator &other) const - { - return current_.data_ == other.current_.data_ && current_.index_ == other.current_.index_; - } - - bool operator!=(const common_iterator &other) const - { - return !(*this == other); - } - - difference_type operator-(const common_iterator &other) const - { - return current_.index_ - other.current_.index_; - } - - common_iterator operator+(size_type offset) - { - common_iterator copy = *this; - size_type end = std::max(0, std::min(current_.end_, current_.index_ + offset)); - - while (copy.current_.index_ != end) - { - end < copy.current_.index_ ? --copy : ++copy; - } - - return copy; - } - - common_iterator &operator--(); - - common_iterator operator--(int) + iterator operator--(int) { iterator old = *this; --*this; @@ -141,46 +89,90 @@ public: return old; } - common_iterator &operator++(); + iterator &operator++(); - common_iterator operator++(int) + iterator operator++(int) { - common_iterator old = *this; + iterator old = *this; ++*this; return old; } - friend class common_iterator; + private: + friend class const_iterator; + + string *parent_; + size_type index_; + }; + + class const_iterator : public std::iterator + { + public: + const_iterator(const string *parent, size_type index); + + const_iterator(const string::iterator &other); + + const_iterator(const const_iterator &other); + + const code_point operator*() const; + + bool operator==(const const_iterator &other) const; + + bool operator!=(const const_iterator &other) const { return !(*this == other); } + + difference_type operator-(const const_iterator &other) const; + + const_iterator &operator+=(int offset); + + const_iterator &operator-=(int offset) { return *this += -offset; } + + const_iterator operator+(int offset); + + const_iterator operator-(int offset) { return *this + (-1 * offset); } + + const_iterator &operator--(); + + const_iterator operator--(int) + { + const_iterator old = *this; + --*this; + + return old; + } + + const_iterator &operator++(); + + const_iterator operator++(int) + { + const_iterator old = *this; + ++*this; + + return old; + } private: - code_point current_; + const string *parent_; + size_type index_; }; - using iterator = common_iterator; - using const_iterator = common_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; static const size_type npos = -1; - static string from(std::int8_t i); - static string from(std::int16_t i); - static string from(std::int32_t i); - static string from(std::int64_t i); - static string from(std::uint8_t i); - static string from(std::uint16_t i); - static string from(std::uint32_t i); - static string from(std::uint64_t i); - static string from(float i); - static string from(double i); - static string from(long double i); + template + static string from(T value); string(); string(string &&str); string(const string &str); string(const string &str, size_type offset); string(const string &str, size_type offset, size_type len); + +#ifdef XLNT_STD_STRING + string(const std::string &str); +#endif string(const utf_mb_wide_string str); string(const utf8_string str); @@ -199,8 +191,8 @@ public: ~string(); - size_type length() const { return length_; } - size_type bytes() const; + size_type length() const; + size_type num_bytes() const; bool empty() const { return length() == 0; } @@ -210,35 +202,33 @@ public: string substr(size_type offset) const; string substr(size_type offset, size_type len) const; - code_point back(); - const code_point back() const; - code_point front(); - const code_point front() const; + code_point back() const; + code_point front() const; - size_type find(code_point c) const; size_type find(char c) const; - size_type find(string str) const; + size_type find(code_point c) const; + size_type find(const string &str) const; - size_type find(code_point c, size_type offset) const; size_type find(char c, size_type offset) const; - size_type find(string str, size_type offset) const; + size_type find(code_point c, size_type offset) const; + size_type find(const string &str, size_type offset) const; - size_type find_last_of(code_point c) const; size_type find_last_of(char c) const; - size_type find_last_of(string str) const; + size_type find_last_of(code_point c) const; + size_type find_last_of(const string &str) const; - size_type find_last_of(code_point c, size_type offset) const; size_type find_last_of(char c, size_type offset) const; - size_type find_last_of(string str, size_type offset) const; + size_type find_last_of(code_point c, size_type offset) const; + size_type find_last_of(const string &str, size_type offset) const; - size_type find_first_of(string str) const; - size_type find_first_of(string str, size_type offset) const; + size_type find_first_of(const string &str) const; + size_type find_first_of(const string &str, size_type offset) const; - size_type find_first_not_of(string str) const; - size_type find_first_not_of(string str, size_type offset) const; + size_type find_first_not_of(const string &str) const; + size_type find_first_not_of(const string &str, size_type offset) const; - size_type find_last_not_of(string str) const; - size_type find_last_not_of(string str, size_type offset) const; + size_type find_last_not_of(const string &str) const; + size_type find_last_not_of(const string &str, size_type offset) const; void clear(); @@ -247,7 +237,7 @@ public: int to_hex() const; - void remove(code_point iter); + void erase(size_type index); iterator begin(); const_iterator begin() const { return cbegin(); } @@ -263,12 +253,13 @@ public: string &operator=(string rhs); - void append(char c); - void append(wchar_t c); - void append(char16_t c); - void append(char32_t c); - void append(string str); + void append(utf_mb_narrow_char c); + void append(utf_mb_wide_char c); + void append(utf16_char c); void append(code_point c); + void append(const string &str); + + void replace(size_type index, utf32_char c); code_point at(size_type index); const code_point at(size_type index) const; @@ -297,8 +288,8 @@ public: private: explicit string(size_type initial_size); - size_type length_; std::vector *data_; + std::unordered_map *code_point_byte_offsets_; }; } // namespace xlnt diff --git a/include/xlnt/workbook/document_security.hpp b/include/xlnt/workbook/document_security.hpp index 1e9386b0..dfc91d68 100644 --- a/include/xlnt/workbook/document_security.hpp +++ b/include/xlnt/workbook/document_security.hpp @@ -25,7 +25,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/workbook/external_book.hpp b/include/xlnt/workbook/external_book.hpp index f0d4e20e..e3a49de6 100644 --- a/include/xlnt/workbook/external_book.hpp +++ b/include/xlnt/workbook/external_book.hpp @@ -1,6 +1,6 @@ #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/workbook/named_range.hpp b/include/xlnt/workbook/named_range.hpp index 8a908c7e..55c9d893 100644 --- a/include/xlnt/workbook/named_range.hpp +++ b/include/xlnt/workbook/named_range.hpp @@ -3,7 +3,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/workbook/theme.hpp b/include/xlnt/workbook/theme.hpp index 4fd5dbad..1fd2cf24 100644 --- a/include/xlnt/workbook/theme.hpp +++ b/include/xlnt/workbook/theme.hpp @@ -1,6 +1,6 @@ #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index 4e5ec0d9..b88e3f50 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -31,7 +31,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/cell_vector.hpp b/include/xlnt/worksheet/cell_vector.hpp index df7621cd..1a44f251 100644 --- a/include/xlnt/worksheet/cell_vector.hpp +++ b/include/xlnt/worksheet/cell_vector.hpp @@ -7,7 +7,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/column_properties.hpp b/include/xlnt/worksheet/column_properties.hpp index 70cc1fee..9bea3495 100644 --- a/include/xlnt/worksheet/column_properties.hpp +++ b/include/xlnt/worksheet/column_properties.hpp @@ -23,7 +23,7 @@ // @author: see AUTHORS file #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/major_order.hpp b/include/xlnt/worksheet/major_order.hpp index 8eaf04fa..fb28bbda 100644 --- a/include/xlnt/worksheet/major_order.hpp +++ b/include/xlnt/worksheet/major_order.hpp @@ -1,6 +1,6 @@ #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/page_margins.hpp b/include/xlnt/worksheet/page_margins.hpp index f4277180..100eb294 100644 --- a/include/xlnt/worksheet/page_margins.hpp +++ b/include/xlnt/worksheet/page_margins.hpp @@ -23,7 +23,7 @@ // @author: see AUTHORS file #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/page_setup.hpp b/include/xlnt/worksheet/page_setup.hpp index cc80b986..4e769734 100644 --- a/include/xlnt/worksheet/page_setup.hpp +++ b/include/xlnt/worksheet/page_setup.hpp @@ -23,7 +23,7 @@ // @author: see AUTHORS file #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/pane.hpp b/include/xlnt/worksheet/pane.hpp index 544b5e1c..3afb7078 100644 --- a/include/xlnt/worksheet/pane.hpp +++ b/include/xlnt/worksheet/pane.hpp @@ -22,7 +22,7 @@ // @author: see AUTHORS file #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/range.hpp b/include/xlnt/worksheet/range.hpp index 6011b61e..217147f3 100644 --- a/include/xlnt/worksheet/range.hpp +++ b/include/xlnt/worksheet/range.hpp @@ -32,7 +32,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/range_reference.hpp b/include/xlnt/worksheet/range_reference.hpp index 100f2022..e58df02a 100644 --- a/include/xlnt/worksheet/range_reference.hpp +++ b/include/xlnt/worksheet/range_reference.hpp @@ -24,7 +24,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/row_properties.hpp b/include/xlnt/worksheet/row_properties.hpp index 619526f3..5771ba06 100644 --- a/include/xlnt/worksheet/row_properties.hpp +++ b/include/xlnt/worksheet/row_properties.hpp @@ -23,7 +23,7 @@ // @author: see AUTHORS file #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/selection.hpp b/include/xlnt/worksheet/selection.hpp index 736dc943..bc403778 100644 --- a/include/xlnt/worksheet/selection.hpp +++ b/include/xlnt/worksheet/selection.hpp @@ -22,7 +22,7 @@ // @author: see AUTHORS file #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/sheet_protection.hpp b/include/xlnt/worksheet/sheet_protection.hpp index 7a2a4166..b8ad2f5f 100644 --- a/include/xlnt/worksheet/sheet_protection.hpp +++ b/include/xlnt/worksheet/sheet_protection.hpp @@ -2,7 +2,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/sheet_view.hpp b/include/xlnt/worksheet/sheet_view.hpp index a17d2b7a..20ea6f5b 100644 --- a/include/xlnt/worksheet/sheet_view.hpp +++ b/include/xlnt/worksheet/sheet_view.hpp @@ -22,7 +22,7 @@ // @author: see AUTHORS file #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/worksheet.hpp b/include/xlnt/worksheet/worksheet.hpp index 68eaf84e..97d6d162 100644 --- a/include/xlnt/worksheet/worksheet.hpp +++ b/include/xlnt/worksheet/worksheet.hpp @@ -33,7 +33,7 @@ #include #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/worksheet/worksheet_properties.hpp b/include/xlnt/worksheet/worksheet_properties.hpp index bca58299..26fe501b 100644 --- a/include/xlnt/worksheet/worksheet_properties.hpp +++ b/include/xlnt/worksheet/worksheet_properties.hpp @@ -23,7 +23,7 @@ // @author: see AUTHORS file #pragma once -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/include/xlnt/xlnt.hpp b/include/xlnt/xlnt.hpp index 2f990c3c..549b179f 100644 --- a/include/xlnt/xlnt.hpp +++ b/include/xlnt/xlnt.hpp @@ -25,7 +25,7 @@ #include -#include "xlnt_config.hpp" +#include #include #include diff --git a/include/xlnt/xlnt_config.hpp b/include/xlnt/xlnt_config.hpp index 0d1856a8..0916fcb7 100644 --- a/include/xlnt/xlnt_config.hpp +++ b/include/xlnt/xlnt_config.hpp @@ -56,18 +56,25 @@ enum class limit_style /// const limit_style LimitStyle = limit_style::openpyxl; -// If no API is defined, assume default +#ifndef XLNT_API #ifdef _MSC_VER -#if !defined(XLNT_API) && defined(SHARED) +#ifdef XLNT_SHARED #ifdef XLNT_EXPORT #define XLNT_API __declspec(dllexport) #else #define XLNT_API __declspec(dllimport) -#endif +#endif // XLNT_EXPORT +#endif // XLNT_SHARED #else #define XLNT_API -#endif -#endif +#endif // _MSC_VER +#endif // XLNT_API + +#ifndef XLNT_STD_STRING +#ifndef XLNT_SHARED +#define XLNT_STD_STRING +#endif // XLNT_SHARED +#endif // XLNT_STD_STRING // If no API for classes is defined, assume default #ifndef XLNT_CLASS diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp index e2ec9621..4651772c 100644 --- a/source/cell/cell.cpp +++ b/source/cell/cell.cpp @@ -144,7 +144,7 @@ bool is_valid_color(const xlnt::string &color) for (std::size_t i = 0; i < color.length(); i++) { - if (std::toupper(color[i].get()) != std::toupper(other[i].get())) + if (std::toupper(color[i]) != std::toupper(other[i])) { return false; } @@ -335,7 +335,7 @@ bool is_valid_locale(const xlnt::string &locale_string) for (auto c : country) { - if (!is_hex(static_cast(std::toupper(c.get())))) + if (!is_hex(static_cast(std::toupper(c)))) { return false; } @@ -699,12 +699,12 @@ xlnt::string format_section(long double number, const section &format, xlnt::cal if (decimal_pos != xlnt::string::npos) { - result[decimal_pos] = ','; + result.replace(decimal_pos, U','); decimal_pos += 3; while (decimal_pos < result.length()) { - result.remove(result.back()); + result.erase(result.length()); } } } @@ -1071,7 +1071,7 @@ bool cell::has_hyperlink() const void cell::set_hyperlink(const string &hyperlink) { - if (hyperlink.length() == 0 || hyperlink.find(':') == std::string::npos) + if (hyperlink.length() == 0 || hyperlink.find(':') == xlnt::string::npos) { throw data_type_exception(); } diff --git a/source/cell/cell_reference.cpp b/source/cell/cell_reference.cpp index 5f64809a..ba798bc1 100644 --- a/source/cell/cell_reference.cpp +++ b/source/cell/cell_reference.cpp @@ -88,71 +88,53 @@ std::pair cell_reference::split_reference(const string &reference { absolute_column = false; absolute_row = false; - - // Convert a coordinate string like 'B12' to a tuple ('B', 12) - bool column_part = true; - - string column_string; - - for (auto character : reference_string) + + auto is_alpha = [](string::code_point c) { - auto upper = std::toupper(character.get(), std::locale::classic()); - - if (std::isalpha(character.get(), std::locale::classic())) - { - if (column_part) - { - column_string.append(upper); - } - else - { - throw cell_coordinates_exception(reference_string); - } - } - else if (character == '$') - { - if (column_part) - { - if (column_string.empty()) - { - column_string.append(upper); - } - else - { - column_part = false; - } - } - } - else - { - if (column_part) - { - column_part = false; - } - else if (!std::isdigit(character.get(), std::locale::classic())) - { - throw cell_coordinates_exception(reference_string); - } - } - } - - string row_string = reference_string.substr(column_string.length()); - - if (row_string.length() == 0) + return (c >= U'A' && c <= U'Z') || (c >= U'a' && c <= U'z'); + }; + + auto upper_ref_string = reference_string.to_upper(); + auto iter = upper_ref_string.begin(); + auto end = upper_ref_string.end(); + + while(iter != end && (is_alpha(*iter) || *iter == U'$')) { - throw cell_coordinates_exception(reference_string); + ++iter; } - - if (column_string[0] == '$') - { - absolute_row = true; - column_string = column_string.substr(1); - } - - if (row_string[0] == '$') + + string column_string(upper_ref_string.begin(), iter); + + if (column_string.length() > 1 && column_string.front() == '$') { absolute_column = true; - row_string = row_string.substr(1); + column_string.erase(0); + } + + if (column_string.length() > 1 && column_string.back() == '$') + { + absolute_row = true; + column_string.erase(column_string.length() - 1); + } + + string row_string(iter, end); + + auto is_digit = [](string::code_point c) + { + return (c >= U'0' && c <= U'9'); + }; + + for(auto c : row_string) + { + if(!is_digit(c)) + { + throw cell_coordinates_exception(reference_string); + } + } + + if (column_string.length() == 0 || row_string.length() == 0) + { + throw cell_coordinates_exception(reference_string); } return { column_string, row_string.to() }; diff --git a/source/cell/tests/test_cell.hpp b/source/cell/tests/test_cell.hpp index 60cad656..85fd13e0 100644 --- a/source/cell/tests/test_cell.hpp +++ b/source/cell/tests/test_cell.hpp @@ -257,7 +257,7 @@ public: TS_ASSERT_THROWS(cell.set_value(str), xlnt::illegal_character_error); } - cell.set_value(xlnt::string("\33")); + cell.set_value(xlnt::string("\41")); // ! cell.set_value(xlnt::string("\t")); // Tab cell.set_value(xlnt::string("\n")); // Newline cell.set_value(xlnt::string("\r")); // Carriage return @@ -361,7 +361,7 @@ public: { /* unsigned char pound = 163; - auto test_string = "Compount Value (" + std::string(pound) + ")"; + auto test_string = "Compount Value (" + xlnt::string(pound) + ")"; auto ws = wb.create_sheet(); cell = ws[xlnt::cell_reference("A1")]; TS_ASSERT_THROWS(cell.check_string(test_string), xlnt::unicode_decode_error); diff --git a/source/cell/types.cpp b/source/cell/types.cpp index 561ac233..dd630ed6 100644 --- a/source/cell/types.cpp +++ b/source/cell/types.cpp @@ -16,15 +16,24 @@ column_t::index_t column_t::column_index_from_string(const string &column_string column_t::index_t column_index = 0; int place = 1; + + auto is_alpha = [](string::code_point c) + { + return (c >= U'A' && c <= U'Z') || (c >= U'a' && c <= U'z'); + }; + + auto column_string_upper = column_string.to_upper(); for (int i = static_cast(column_string.length()) - 1; i >= 0; i--) { - if (!std::isalpha(column_string[static_cast(i)].get(), std::locale::classic())) + auto index = static_cast(i); + + if (!is_alpha(column_string[index])) { throw column_string_index_exception(); } - auto char_index = std::toupper(column_string[static_cast(i)].get(), std::locale::classic()) - U'A'; + auto char_index = column_string_upper[index] - U'A'; column_index += static_cast((char_index + 1) * place); place *= 26; diff --git a/source/detail/cell_impl.hpp b/source/detail/cell_impl.hpp index e641750e..b2feed50 100644 --- a/source/detail/cell_impl.hpp +++ b/source/detail/cell_impl.hpp @@ -30,11 +30,11 @@ xlnt::string check_string(xlnt::string s) s = s.substr(0, 32767); // max string length in Excel } - for (xlnt::string::code_point c : s) + for (auto c : s) { - if (c >= 0 && (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31))) + if (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31)) { - throw xlnt::illegal_character_error(0); + throw xlnt::illegal_character_error(c); } } @@ -68,7 +68,49 @@ std::pair cast_percentage(const xlnt::string &s) std::pair cast_time(const xlnt::string &s) { xlnt::time result; - return { false, result }; + + try + { + auto last_colon = s.find_last_of(':'); + + if (last_colon == xlnt::string::npos) + { + return { false, result }; + } + + double seconds = s.substr(last_colon + 1).to(); + result.second = static_cast(seconds); + result.microsecond = static_cast((seconds - static_cast(result.second)) * 1e6); + + auto first_colon = s.find(':'); + + if (first_colon == last_colon) + { + auto decimal_pos = s.find('.'); + + if (decimal_pos != xlnt::string::npos) + { + result.minute = s.substr(0, first_colon).to(); + } + else + { + result.hour = s.substr(0, first_colon).to(); + result.minute = result.second; + result.second = 0; + } + } + else + { + result.hour = s.substr(0, first_colon).to(); + result.minute = s.substr(first_colon + 1, last_colon - first_colon - 1).to(); + } + } + catch (std::invalid_argument) + { + return { false, result }; + } + + return { true, result }; } } // namespace diff --git a/source/detail/comment_impl.hpp b/source/detail/comment_impl.hpp index f3229e46..75272f18 100644 --- a/source/detail/comment_impl.hpp +++ b/source/detail/comment_impl.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace xlnt { namespace detail { diff --git a/source/detail/constants.cpp b/source/detail/constants.cpp index 0dac013c..56c2c17c 100644 --- a/source/detail/constants.cpp +++ b/source/detail/constants.cpp @@ -2,7 +2,7 @@ #include -#include "xlnt_config.hpp" +#include namespace xlnt { diff --git a/source/packaging/zip_file.cpp b/source/packaging/zip_file.cpp index dc832e0c..320f405a 100644 --- a/source/packaging/zip_file.cpp +++ b/source/packaging/zip_file.cpp @@ -289,7 +289,7 @@ void zip_file::append_comment() auto comment_length = std::min(static_cast(comment.length()), std::numeric_limits::max()); buffer_[buffer_.size() - 2] = static_cast(comment_length); buffer_[buffer_.size() - 1] = static_cast(comment_length >> 8); - std::copy(comment.data(), comment.data() + comment.bytes(), std::back_inserter(buffer_)); + std::copy(comment.data(), comment.data() + comment.num_bytes(), std::back_inserter(buffer_)); } } diff --git a/source/serialization/workbook_serializer.cpp b/source/serialization/workbook_serializer.cpp index 7eba316f..f7892c1b 100644 --- a/source/serialization/workbook_serializer.cpp +++ b/source/serialization/workbook_serializer.cpp @@ -225,7 +225,7 @@ xml_document workbook_serializer::write_workbook() const sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/')); auto iter = sheet_index_string.end(); --iter; - while (isdigit((*iter).get())) + while (isdigit(*iter)) --iter; auto first_digit = iter - sheet_index_string.begin(); sheet_index_string = sheet_index_string.substr(static_cast(first_digit + 1)); diff --git a/source/utils/exceptions.cpp b/source/utils/exceptions.cpp index 942badc8..0ab9f334 100644 --- a/source/utils/exceptions.cpp +++ b/source/utils/exceptions.cpp @@ -34,7 +34,7 @@ cell_coordinates_exception::cell_coordinates_exception(const string &coord_strin { } -illegal_character_error::illegal_character_error(char c) +illegal_character_error::illegal_character_error(xlnt::utf32_char c) { } diff --git a/source/utils/string.cpp b/source/utils/string.cpp index 3f9c35e5..8907ad74 100644 --- a/source/utils/string.cpp +++ b/source/utils/string.cpp @@ -1,8 +1,11 @@ #include +#include #include #include #include #include +//TODO: make this conditional on XLNT_STD_STRING once std::sto* functions are replaced +#include #include #include @@ -12,7 +15,7 @@ namespace { template -std::size_t count_bytes(const T *arr) +std::size_t string_length(const T *arr) { std::size_t i = 0; @@ -24,153 +27,229 @@ std::size_t count_bytes(const T *arr) return i; } +xlnt::string::code_point to_upper(xlnt::string::code_point p) +{ + if(p >= U'a' && p <= U'z') + { + return U'A' + p - U'a'; + } + + return p; +} + +xlnt::string::code_point to_lower(xlnt::string::code_point p) +{ + if(p >= U'A' && p <= U'Z') + { + return U'a' + p - U'A'; + } + + return p; +} + } namespace xlnt { -bool string::code_point::operator==(char rhs) const -{ - return get() == rhs; -} - -bool string::code_point::operator!=(char rhs) const -{ - return get() != rhs; -} - -bool string::code_point::operator<(char rhs) const -{ - return char(get()) < rhs; -} - -bool string::code_point::operator<=(char rhs) const -{ - return char(get()) <= rhs; -} - -bool string::code_point::operator>(char rhs) const -{ - return char(get()) > rhs; -} - -bool string::code_point::operator>=(char rhs) const -{ - return char(get()) >= rhs; -} - +template<> string string::from(std::int8_t i) { return string(std::to_string(i).c_str()); } +template<> string string::from(std::int16_t i) { return string(std::to_string(i).c_str()); } +template<> string string::from(std::int32_t i) { return string(std::to_string(i).c_str()); } +template<> string string::from(std::int64_t i) { return string(std::to_string(i).c_str()); } +template<> string string::from(std::uint8_t i) { return string(std::to_string(i).c_str()); } +template<> string string::from(std::uint16_t i) { return string(std::to_string(i).c_str()); } +template<> string string::from(std::uint32_t i) { return string(std::to_string(i).c_str()); } +template<> string string::from(std::uint64_t i) { return string(std::to_string(i).c_str()); } +template<> +string string::from(std::size_t i) +{ + return string(std::to_string(i).c_str()); +} + +template<> string string::from(float i) { return string(std::to_string(i).c_str()); } +template<> string string::from(double i) { return string(std::to_string(i).c_str()); } +template<> string string::from(long double i) { return string(std::to_string(i).c_str()); } -string::code_point &string::code_point::operator=(string::utf32_char value) -{ - utf8::append(value, data_ + index_); - - return *this; -} - -string::utf32_char string::code_point::get() const -{ - return utf8::peek_next(data_ + index_, data_ + end_); -} - +#ifdef XLNT_STD_STRING template<> -xlnt::string::common_iterator &xlnt::string::common_iterator::operator--() +string string::from(const std::string &s) { - auto iter = current_.data_ + current_.index_; - utf8::prior(iter, current_.data_); - current_.index_ = iter - current_.data_; + return string(s.data()); +} +#endif - return *this; +xlnt::string::iterator::iterator(xlnt::string *parent, size_type index) + : parent_(parent), + index_(index) +{ } -template<> -xlnt::string::common_iterator &xlnt::string::common_iterator::operator--() +xlnt::string::iterator::iterator(const xlnt::string::iterator &other) + : parent_(other.parent_), + index_(other.index_) { - auto iter = current_.data_ + current_.index_; - utf8::prior(iter, current_.data_); - current_.index_ = iter - current_.data_; - - return *this; } -template<> -xlnt::string::common_iterator &xlnt::string::common_iterator::operator++() +string::code_point xlnt::string::iterator::operator*() { - auto iter = current_.data_ + current_.index_; - utf8::advance(iter, 1, current_.data_ + current_.end_); - current_.index_ = iter - current_.data_; - - return *this; + return parent_->at(index_); } -template<> -xlnt::string::common_iterator &xlnt::string::common_iterator::operator++() +bool xlnt::string::iterator::operator==(const iterator &other) const { - auto iter = current_.data_ + current_.index_; - utf8::advance(iter, 1, current_.data_ + current_.end_); - current_.index_ = iter - current_.data_; + return parent_ == other.parent_ && index_ == other.index_; +} - return *this; +string::difference_type string::iterator::operator-(const iterator &other) const +{ + return index_ - other.index_; +} + +xlnt::string::const_iterator::const_iterator(const xlnt::string *parent, size_type index) + : parent_(parent), + index_(index) +{ +} + +xlnt::string::const_iterator::const_iterator(const xlnt::string::iterator &other) + : parent_(other.parent_), + index_(other.index_) +{ +} + +xlnt::string::const_iterator::const_iterator(const xlnt::string::const_iterator &other) + : parent_(other.parent_), + index_(other.index_) +{ +} + +string::difference_type string::const_iterator::operator-(const const_iterator &other) const +{ + return index_ - other.index_; +} + +const string::code_point xlnt::string::const_iterator::operator*() const +{ + return parent_->at(index_); +} + +bool xlnt::string::const_iterator::operator==(const const_iterator &other) const +{ + return parent_ == other.parent_ && index_ == other.index_; +} + +xlnt::string::iterator &xlnt::string::iterator::operator--() +{ + return *this -= 1; +} + +xlnt::string::const_iterator &xlnt::string::const_iterator::operator--() +{ + return *this -= 1; +} + +xlnt::string::iterator &xlnt::string::iterator::operator++() +{ + return *this += 1; +} + +xlnt::string::const_iterator &xlnt::string::const_iterator::operator++() +{ + return *this += 1; +} + +string::const_iterator &string::const_iterator::operator+=(int offset) +{ + auto new_index = index_ + offset; + new_index = std::max(0, std::min(parent_->length(), new_index)); + index_ = static_cast(new_index); + + return *this; +} + +xlnt::string::iterator xlnt::string::iterator::operator+(int offset) +{ + iterator copy = *this; + + auto new_index = index_ + offset; + new_index = std::max(0, std::min(parent_->length(), new_index)); + copy.index_ = static_cast(new_index); + + return copy; +} + +xlnt::string::const_iterator xlnt::string::const_iterator::operator+(int offset) +{ + const_iterator copy = *this; + + auto new_index = index_ + offset; + new_index = std::max(0, std::min(parent_->length(), new_index)); + copy.index_ = static_cast(new_index); + + return copy; } string::string(size_type initial_size) - : length_(0), - data_(new std::vector) + : data_(new std::vector), + code_point_byte_offsets_(new std::unordered_map) { data_->resize(initial_size + 1); data_->back() = '\0'; + + code_point_byte_offsets_->insert({0, 0}); } string::string() : string(size_type(0)) @@ -182,7 +261,9 @@ string::string(string &&str) : string() swap(*this, str); } -string::string(const string &str) : string(str, 0) +string::string(const string &str) + : data_(new std::vector(*str.data_)), + code_point_byte_offsets_(new std::unordered_map(*str.code_point_byte_offsets_)) { } @@ -192,58 +273,100 @@ string::string(const string &str, size_type offset) : string(str, offset, str.le string::string(const string &str, size_type offset, size_type len) : string() { - *this = str.substr(offset, len); + auto part = str.substr(offset, len); + + *data_ = *part.data_; + *code_point_byte_offsets_ = *part.code_point_byte_offsets_; } +#ifdef XLNT_STD_STRING +string::string(const std::string &str) : string(str.data()) +{ +} +#endif + string::string(const utf_mb_wide_string str) : string() { - data_->clear(); - utf8::utf16to8(str, str + count_bytes(str), std::back_inserter(*data_)); - data_->push_back('\0'); - - length_ = utf8::distance(data(), data() + data_->size() - 1); + auto iter = str; + + while(*iter != '\0') + { + append(*iter); + iter++; + } } string::string(const utf8_string str) : string() { - data_->clear(); - std::copy(str, str + count_bytes(str), std::back_inserter(*data_)); - data_->push_back('\0'); - - length_ = utf8::distance(data(), data() + data_->size() - 1); + auto start = str; + auto end = str; + + while(*end != '\0') + { + ++end; + } + + auto iter = start; + + while(iter != end) + { + append((utf32_char)utf8::next(iter, end)); + } } string::string(const utf16_string str) : string() { - data_->clear(); - utf8::utf16to8(str, str + count_bytes(str), std::back_inserter(*data_)); - data_->push_back('\0'); - - length_ = utf8::distance(data(), data() + data_->size() - 1); + auto iter = str; + + while(*iter != '\0') + { + append(*iter); + iter++; + } } string::string(const utf32_string str) : string() { - data_->clear(); - utf8::utf32to8(str, str + count_bytes(str), std::back_inserter(*data_)); - data_->push_back('\0'); - - length_ = utf8::distance(data(), data() + data_->size() - 1); +auto iter = str; + + while(*iter != '\0') + { + append(*iter); + iter++; + } } string::~string() { delete data_; + data_ = nullptr; + delete code_point_byte_offsets_; + code_point_byte_offsets_ = nullptr; } string string::to_upper() const { - return *this; + string upper; + + for(auto c : *this) + { + upper.append(::to_upper(c)); + } + + return upper; } string string::to_lower() const { - return *this; + + string lower; + + for(auto c : *this) + { + lower.append(::to_lower(c)); + } + + return lower; } string string::substr(size_type offset) const @@ -253,37 +376,22 @@ string string::substr(size_type offset) const string string::substr(size_type offset, size_type len) const { - auto iter = begin() + offset; - size_type i = 0; - string result; - - while (i++ < len && iter != end()) - { - result.append(*iter); - ++iter; - } - - return result; + if(len != npos && offset + len < length()) + { + return string(begin() + offset, begin() + (offset + len)); + } + + return string(begin() + offset, end()); } -string::code_point string::back() +string::code_point string::back() const { - return *(begin() + length_ + -1); + return at(length() - 1); } -const string::code_point string::back() const +string::code_point string::front() const { - return *(begin() + length_ + -1); -} - -string::code_point string::front() -{ - return *begin(); -} - -const string::code_point string::front() const -{ - return *begin(); + return at(0); } string::size_type string::find(code_point c) const @@ -296,7 +404,7 @@ string::size_type string::find(char c) const return find(c, 0); } -string::size_type string::find(string str) const +string::size_type string::find(const string &str) const { return find(str, 0); } @@ -305,24 +413,6 @@ string::size_type string::find(code_point c, size_type offset) const { auto iter = begin() + offset; - while (iter != end()) - { - if ((*iter).get() == c.get()) - { - return offset; - } - - ++iter; - offset++; - } - - return npos; -} - -string::size_type string::find(char c, size_type offset) const -{ - auto iter = begin() + offset; - while (iter != end()) { if (*iter == c) @@ -337,9 +427,24 @@ string::size_type string::find(char c, size_type offset) const return npos; } -string::size_type string::find(string str, size_type offset) const +string::size_type string::find(char c, size_type offset) const { - return 0; + return find(static_cast(c), offset); +} + +string::size_type string::find(const string &str, size_type offset) const +{ + while (offset < length() - str.length()) + { + if (substr(offset, str.length()) == str) + { + return offset; + } + + offset++; + } + + return npos; } string::size_type string::find_last_of(code_point c) const @@ -352,60 +457,124 @@ string::size_type string::find_last_of(char c) const return find_last_of(c, 0); } -string::size_type string::find_last_of(string str) const +string::size_type string::find_last_of(const string &str) const { return find_last_of(str, 0); } string::size_type string::find_last_of(code_point c, size_type offset) const { - return 0; + auto stop = begin() + offset; + auto iter = end() - 1; + + while (iter != stop) + { + if (*iter == c) + { + return iter - begin(); + } + + --iter; + } + + return *stop == c ? offset : npos; } string::size_type string::find_last_of(char c, size_type offset) const { - return 0; + return find_last_of(static_cast(c), offset); } -string::size_type string::find_last_of(string str, size_type offset) const +string::size_type string::find_last_of(const string &str, size_type offset) const { - return 0; + auto stop = begin() + offset; + auto iter = end() - 1; + + while (iter != stop) + { + if(str.find(*iter) != npos) + { + return iter - begin(); + } + + --iter; + } + + return npos; } -string::size_type string::find_first_of(string str) const +string::size_type string::find_first_of(const string &str) const { return find_first_of(str, 0); } -string::size_type string::find_first_of(string str, size_type offset) const +string::size_type string::find_first_of(const string &str, size_type offset) const { - return 0; + auto iter = begin() + offset; + + while (iter != end()) + { + if(str.find(*iter) != npos) + { + return iter - begin(); + } + + ++iter; + } + + return npos; } -string::size_type string::find_first_not_of(string str) const +string::size_type string::find_first_not_of(const string &str) const { return find_first_not_of(str, 0); } -string::size_type string::find_first_not_of(string str, size_type offset) const +string::size_type string::find_first_not_of(const string &str, size_type offset) const { - return 0; + auto iter = begin() + offset; + + while (iter != end()) + { + if(str.find(*iter) == npos) + { + return iter - begin(); + } + + ++iter; + } + + return npos; } -string::size_type string::find_last_not_of(string str) const +string::size_type string::find_last_not_of(const string &str) const { return find_last_not_of(str, 0); } -string::size_type string::find_last_not_of(string str, size_type offset) const +string::size_type string::find_last_not_of(const string &str, size_type offset) const { - return 0; + auto stop = begin() + offset; + auto iter = end() - 1; + + while (iter != stop) + { + if(str.find(*iter) == npos) + { + return iter - begin(); + } + + --iter; + } + + return npos; } void string::clear() { - length_ = 0; data_->clear(); data_->push_back('\0'); + code_point_byte_offsets_->clear(); + code_point_byte_offsets_->insert({0, 0}); } template<> @@ -432,14 +601,40 @@ long double string::to() const return std::stold(std::string(data())); } +template<> +double string::to() const +{ + return std::stod(std::string(data())); +} + +#ifdef XLNT_STD_STRING +template<> +std::string string::to() const +{ + return std::string(data()); +} +#endif + int string::to_hex() const { return 0; } -void string::remove(code_point iter) +void string::erase(size_type index) { - + auto start = code_point_byte_offsets_->at(index); + auto next_start = code_point_byte_offsets_->at(index + 1); + + data_->erase(data_->begin() + start, data_->begin() + next_start); + + auto code_point_bytes = next_start - start; + + for(size_type i = index + 1; i < length(); i++) + { + code_point_byte_offsets_->at(i) = code_point_byte_offsets_->at(i + 1) - code_point_bytes; + } + + code_point_byte_offsets_->erase(code_point_byte_offsets_->find(length())); } string &string::operator=(string rhs) @@ -451,22 +646,22 @@ string &string::operator=(string rhs) string::iterator string::begin() { - return iterator(data(), 0, length_); + return iterator(this, 0); } string::const_iterator string::cbegin() const { - return const_iterator(data(), 0, length_); + return const_iterator(this, 0); } string::iterator string::end() { - return iterator(data(), length_, length_); + return iterator(this, length()); } string::const_iterator string::cend() const { - return const_iterator(data(), length_, length_); + return const_iterator(this, length()); } string::byte_pointer string::data() @@ -485,7 +680,7 @@ std::size_t string::hash() const return hasher(std::string(data())); } -std::size_t string::bytes() const +std::size_t string::num_bytes() const { return data_->size(); } @@ -494,38 +689,68 @@ void string::append(char c) { data_->back() = c; data_->push_back('\0'); - - length_++; + + code_point_byte_offsets_->insert({length() + 1, num_bytes() - 1}); } void string::append(wchar_t c) { + if(c < 128) + { + append(static_cast(c)); + return; + } + data_->pop_back(); - utf8::utf16to8(&c, &c + 1, std::back_inserter(*data_)); + + std::array utf8_encoded {{0}}; + auto end = utf8::utf16to8(&c, &c + 1, utf8_encoded.begin()); + std::copy(utf8_encoded.begin(), end, std::back_inserter(*data_)); + data_->push_back('\0'); - - length_++; + + code_point_byte_offsets_->insert({length() + 1, num_bytes() - 1}); } void string::append(char16_t c) { + if(c < 128) + { + append(static_cast(c)); + return; + } + data_->pop_back(); - utf8::utf16to8(&c, &c + 1, std::back_inserter(*data_)); + + std::array utf8_encoded {{0}}; + auto end = utf8::utf16to8(&c, &c + 1, utf8_encoded.begin()); + std::copy(utf8_encoded.begin(), end, std::back_inserter(*data_)); + data_->push_back('\0'); - - length_++; + + code_point_byte_offsets_->insert({length() + 1, num_bytes() - 1}); } -void string::append(char32_t c) +void string::append(code_point c) { + if(c < 128) + { + append(static_cast(c)); + return; + } + data_->pop_back(); - utf8::utf32to8(&c, &c + 1, std::back_inserter(*data_)); - data_->push_back('\0'); + + std::array utf8_encoded {{0}}; + auto end = utf8::utf32to8(&c, &c + 1, utf8_encoded.begin()); + std::copy(utf8_encoded.begin(), end, std::back_inserter(*data_)); - length_++; + data_->push_back('\0'); + + code_point_byte_offsets_->insert({length() + 1, num_bytes() - 1}); } -void string::append(string str) +void string::append(const string &str) { for (auto c : str) { @@ -533,19 +758,61 @@ void string::append(string str) } } -void string::append(code_point c) +void string::replace(size_type index, utf32_char value) { - append(c.get()); + std::array encoded = {{0}}; + auto encoded_end = utf8::utf32to8(&value, &value + 1, encoded.begin()); + auto encoded_len = encoded_end - encoded.begin(); + + auto data_start = code_point_byte_offsets_->at(index); + auto data_end = code_point_byte_offsets_->at(index + 1); + + auto previous_len = data_end - data_start; + int difference = encoded_len - previous_len; + + if(difference < 0) + { + data_->erase(data_->begin() + data_end + difference, data_->begin() + data_end); + } + else if(difference > 0) + { + data_->insert(data_->begin() + data_start, difference, '\0'); + } + + for(std::size_t i = index + 1; i < code_point_byte_offsets_->size(); i++) + { + code_point_byte_offsets_->at(i) += difference; + } + + auto iter = encoded.begin(); + auto data_iter = data_->begin() + data_start; + + while(iter != encoded_end) + { + *data_iter = *iter; + ++data_iter; + ++iter; + } } string::code_point string::at(size_type index) { - return *(begin() + index); + if(index == length()) + { + return U'\0'; + } + + return utf8::peek_next(data_->begin() + code_point_byte_offsets_->at(index), data_->end()); } const string::code_point string::at(size_type index) const { - return *(begin() + index); + if(index == length()) + { + return U'\0'; + } + + return utf8::peek_next(data_->begin() + code_point_byte_offsets_->at(index), data_->end()); } bool string::operator==(const_byte_pointer str) const @@ -562,7 +829,7 @@ bool string::operator==(const string &str) const while (left_iter != end() && right_iter != str.end()) { - if ((*left_iter).get() != (*right_iter).get()) + if (*left_iter != *right_iter) { return false; } @@ -603,8 +870,8 @@ void swap(string &left, string &right) { using std::swap; - swap(left.length_, right.length_); swap(left.data_, right.data_); + swap(left.code_point_byte_offsets_, right.code_point_byte_offsets_); } std::ostream &operator<<(std::ostream &left, string &right) @@ -631,4 +898,9 @@ bool string::operator<(const string &other) const return std::string(data()) < std::string(other.data()); } +string::size_type string::length() const +{ + return code_point_byte_offsets_->size() - 1; +} + } // namespace xlnt diff --git a/source/workbook/named_range.cpp b/source/workbook/named_range.cpp index d23b9384..ed744fa4 100644 --- a/source/workbook/named_range.cpp +++ b/source/workbook/named_range.cpp @@ -27,7 +27,8 @@ std::vector split_string(const xlnt::string &string, char delim) separator_index = string.find(delim, previous_index); } - split.push_back(string.substr(previous_index)); + auto part = string.substr(previous_index); + split.push_back(part); return split; } diff --git a/source/workbook/tests/test_workbook.hpp b/source/workbook/tests/test_workbook.hpp index b8c7056e..d0f780de 100644 --- a/source/workbook/tests/test_workbook.hpp +++ b/source/workbook/tests/test_workbook.hpp @@ -47,9 +47,9 @@ public: { xlnt::workbook wb; auto new_sheet = wb.create_sheet(); - std::string title = "my sheet"; - new_sheet.set_title(title.c_str()); - auto found_sheet = wb.get_sheet_by_name(title.c_str()); + xlnt::string title = "my sheet"; + new_sheet.set_title(title); + auto found_sheet = wb.get_sheet_by_name(title); TS_ASSERT_EQUALS(new_sheet, found_sheet); } @@ -120,9 +120,9 @@ public: { xlnt::workbook wb; auto new_sheet = wb.create_sheet(); - std::string title = "my sheet"; - new_sheet.set_title(title.c_str()); - auto found_sheet = wb.get_sheet_by_name(title.c_str()); + xlnt::string title = "my sheet"; + new_sheet.set_title(title); + auto found_sheet = wb.get_sheet_by_name(title); TS_ASSERT_EQUALS(new_sheet, found_sheet); } diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index 7e51efc7..2711f73f 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -351,7 +351,7 @@ std::size_t workbook::index_from_ws_filename(const string &ws_filename) sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/')); auto iter = sheet_index_string.end(); --iter; - while (isdigit((*iter).get())) + while (isdigit((*iter))) --iter; auto first_digit = static_cast(iter - sheet_index_string.begin()); sheet_index_string = sheet_index_string.substr(first_digit + 1); @@ -388,9 +388,9 @@ worksheet workbook::create_sheet(const string &title) throw sheet_title_exception(title); } - if (std::find_if(title.data(), title.data() + title.bytes(), [](char c) { + if (std::find_if(title.data(), title.data() + title.num_bytes(), [](char c) { return c == '*' || c == ':' || c == '/' || c == '\\' || c == '?' || c == '[' || c == ']'; - }) != title.data() + title.bytes()) + }) != title.data() + title.num_bytes()) { throw sheet_title_exception(title); } diff --git a/source/worksheet/sheet_protection.cpp b/source/worksheet/sheet_protection.cpp index b03e1655..4fabf1c9 100644 --- a/source/worksheet/sheet_protection.cpp +++ b/source/worksheet/sheet_protection.cpp @@ -23,7 +23,7 @@ string sheet_protection::hash_password(const string &plaintext_password) { int password = 0x0000; - for (int i = 1; i <= plaintext_password.bytes(); i++) + for (int i = 1; i <= plaintext_password.num_bytes(); i++) { char character = plaintext_password.data()[i - 1]; int value = character << i; @@ -33,13 +33,13 @@ string sheet_protection::hash_password(const string &plaintext_password) i++; } - password ^= plaintext_password.bytes(); + password ^= plaintext_password.num_bytes(); password ^= 0xCE4B; string hashed = int_to_hex(password); auto iter = hashed.data(); - while (iter != hashed.data() + hashed.bytes()) + while (iter != hashed.data() + hashed.num_bytes()) { *iter = std::toupper(*iter, std::locale::classic()); } diff --git a/tests/helpers/helper.hpp b/tests/helpers/helper.hpp index dd461a41..636bea08 100644 --- a/tests/helpers/helper.hpp +++ b/tests/helpers/helper.hpp @@ -55,13 +55,13 @@ public: return compare_xml(expected_xml.get_root(), observed.get_root()); } - static comparison_result compare_xml(const std::string &left_contents, const std::string &right_contents) + static comparison_result compare_xml(const xlnt::string &left_contents, const xlnt::string &right_contents) { xlnt::xml_document left_xml; - left_xml.from_string(left_contents.c_str()); + left_xml.from_string(left_contents.data()); xlnt::xml_document right_xml; - right_xml.from_string(right_contents.c_str()); + right_xml.from_string(right_contents.data()); return compare_xml(left_xml.get_root(), right_xml.get_root()); } diff --git a/tests/helpers/path_helper.hpp b/tests/helpers/path_helper.hpp index 899f51fc..277ac9e2 100644 --- a/tests/helpers/path_helper.hpp +++ b/tests/helpers/path_helper.hpp @@ -62,7 +62,7 @@ public: if (_NSGetExecutablePath(path.data(), &size) == 0) { - return std::string(path.begin(), std::find(path.begin(), path.end(), '\0') - 9); + return xlnt::string(path.begin(), std::find(path.begin(), path.end(), '\0') - 9); } throw std::runtime_error("buffer too small, " + std::to_string(path.size()) + ", should be: " + std::to_string(size)); @@ -126,7 +126,7 @@ public: { struct stat fileAtt; - if (stat(path.c_str(), &fileAtt) == 0) + if (stat(path.data(), &fileAtt) == 0) { return S_ISREG(fileAtt.st_mode); } diff --git a/tests/helpers/temporary_directory.hpp b/tests/helpers/temporary_directory.hpp index 9d9a91d6..06249c21 100644 --- a/tests/helpers/temporary_directory.hpp +++ b/tests/helpers/temporary_directory.hpp @@ -11,7 +11,7 @@ class TemporaryDirectory { public: - static std::string CreateTemporaryFilename() + static xlnt::string CreateTemporaryFilename() { #ifdef _WIN32 std::array buffer; @@ -24,7 +24,7 @@ public: { throw std::runtime_error("GetTempPath failed"); } - std::string directory(buffer.begin(), buffer.begin() + result); + xlnt::string directory(buffer.begin(), buffer.begin() + result); return PathHelper::WindowsToUniversalPath(directory + "xlnt"); #else return "/tmp/xlsx"; @@ -41,8 +41,8 @@ public: remove(filename_.c_str()); } - std::string GetFilename() const { return filename_; } + xlnt::string GetFilename() const { return filename_; } private: - const std::string filename_; + const xlnt::string filename_; };