diff options
Diffstat (limited to 'lib/charset')
| -rw-r--r-- | lib/charset/README | 2 | ||||
| -rw-r--r-- | lib/charset/utf8.h | 80 | ||||
| -rw-r--r-- | lib/charset/utf8/checked.h | 176 | ||||
| -rw-r--r-- | lib/charset/utf8/core.h | 275 | ||||
| -rw-r--r-- | lib/charset/utf8/cpp11.h | 70 | ||||
| -rw-r--r-- | lib/charset/utf8/cpp17.h | 96 | ||||
| -rw-r--r-- | lib/charset/utf8/cpp20.h | 124 | ||||
| -rw-r--r-- | lib/charset/utf8/unchecked.h | 163 | 
8 files changed, 771 insertions, 215 deletions
| diff --git a/lib/charset/README b/lib/charset/README index b20f76b..3217b87 100644 --- a/lib/charset/README +++ b/lib/charset/README @@ -1,2 +1,2 @@  This UTF-8 to EBU charset (defined in ETSI TS 101 756v1.8.1) was copied from -ODR-PadEnc. +ODR-PadEnc, with utf8 library v4.0.5 from https://github.com/nemtrif/utfcpp/tree/master/source/utf8 diff --git a/lib/charset/utf8.h b/lib/charset/utf8.h index 4e44514..b513530 100644 --- a/lib/charset/utf8.h +++ b/lib/charset/utf8.h @@ -1,34 +1,46 @@ -// Copyright 2006 Nemanja Trifunovic
 -
 -/*
 -Permission is hereby granted, free of charge, to any person or organization
 -obtaining a copy of the software and accompanying documentation covered by
 -this license (the "Software") to use, reproduce, display, distribute,
 -execute, and transmit the Software, and to prepare derivative works of the
 -Software, and to permit third-parties to whom the Software is furnished to
 -do so, all subject to the following:
 -
 -The copyright notices in the Software and this entire statement, including
 -the above license grant, this restriction and the following disclaimer,
 -must be included in all copies of the Software, in whole or in part, and
 -all derivative works of the Software, unless such copies or derivative
 -works are solely in the form of machine-executable object code generated by
 -a source language processor.
 -
 -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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 -DEALINGS IN THE SOFTWARE.
 -*/
 -
 -
 -#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
 -#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
 -
 -#include "utf8/checked.h"
 -#include "utf8/unchecked.h"
 -
 -#endif // header guard
 +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +/* +To control the C++ language version used by the library, you can define UTF_CPP_CPLUSPLUS macro +and set it to one of the values used by the __cplusplus predefined macro. + +For instance, +    #define UTF_CPP_CPLUSPLUS 199711L +will cause the UTF-8 CPP library to use only types and language features available in the C++ 98 standard. +Some library features will be disabled. + +If you leave UTF_CPP_CPLUSPLUS undefined, it will be internally assigned to __cplusplus. +*/ + +#include "utf8/checked.h" +#include "utf8/unchecked.h" + +#endif // header guard diff --git a/lib/charset/utf8/checked.h b/lib/charset/utf8/checked.h index 1331155..98949f8 100644 --- a/lib/charset/utf8/checked.h +++ b/lib/charset/utf8/checked.h @@ -1,4 +1,4 @@ -// Copyright 2006 Nemanja Trifunovic +// Copyright 2006-2016 Nemanja Trifunovic  /*  Permission is hereby granted, free of charge, to any person or organization @@ -39,64 +39,62 @@ namespace utf8      // Exceptions that may be thrown from the library functions.      class invalid_code_point : public exception { -        uint32_t cp; +        utfchar32_t cp;      public: -        invalid_code_point(uint32_t cp) : cp(cp) {} -        virtual const char* what() const throw() { return "Invalid code point"; } -        uint32_t code_point() const {return cp;} +        invalid_code_point(utfchar32_t codepoint) : cp(codepoint) {} +        virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid code point"; } +        utfchar32_t code_point() const {return cp;}      };      class invalid_utf8 : public exception { -        uint8_t u8; +        utfchar8_t u8;      public: -        invalid_utf8 (uint8_t u) : u8(u) {} -        virtual const char* what() const throw() { return "Invalid UTF-8"; } -        uint8_t utf8_octet() const {return u8;} +        invalid_utf8 (utfchar8_t u) : u8(u) {} +        invalid_utf8 (char c) : u8(static_cast<utfchar8_t>(c)) {} +        virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-8"; } +        utfchar8_t utf8_octet() const {return u8;}      };      class invalid_utf16 : public exception { -        uint16_t u16; +        utfchar16_t u16;      public: -        invalid_utf16 (uint16_t u) : u16(u) {} -        virtual const char* what() const throw() { return "Invalid UTF-16"; } -        uint16_t utf16_word() const {return u16;} +        invalid_utf16 (utfchar16_t u) : u16(u) {} +        virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-16"; } +        utfchar16_t utf16_word() const {return u16;}      };      class not_enough_room : public exception {      public: -        virtual const char* what() const throw() { return "Not enough space"; } +        virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Not enough space"; }      };      /// The library API - functions intended to be called by the users      template <typename octet_iterator> -    octet_iterator append(uint32_t cp, octet_iterator result) +    octet_iterator append(utfchar32_t cp, octet_iterator result)      {          if (!utf8::internal::is_code_point_valid(cp))              throw invalid_code_point(cp); -        if (cp < 0x80)                        // one octet -            *(result++) = static_cast<uint8_t>(cp); -        else if (cp < 0x800) {                // two octets -            *(result++) = static_cast<uint8_t>((cp >> 6)            | 0xc0); -            *(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80); -        } -        else if (cp < 0x10000) {              // three octets -            *(result++) = static_cast<uint8_t>((cp >> 12)           | 0xe0); -            *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f)   | 0x80); -            *(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80); -        } -        else {                                // four octets -            *(result++) = static_cast<uint8_t>((cp >> 18)           | 0xf0); -            *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)  | 0x80); -            *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f)   | 0x80); -            *(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80); -        } -        return result; +        return internal::append(cp, result); +    } + +    inline void append(utfchar32_t cp, std::string& s) +    { +        append(cp, std::back_inserter(s)); +    } + +    template <typename word_iterator> +    word_iterator append16(utfchar32_t cp, word_iterator result) +    { +        if (!utf8::internal::is_code_point_valid(cp)) +            throw invalid_code_point(cp); + +        return internal::append16(cp, result);      }      template <typename octet_iterator, typename output_iterator> -    output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) +    output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, utfchar32_t replacement)      {          while (start != end) {              octet_iterator sequence_start = start; @@ -107,7 +105,9 @@ namespace utf8                          *out++ = *it;                      break;                  case internal::NOT_ENOUGH_ROOM: -                    throw not_enough_room(); +                    out = utf8::append (replacement, out); +                    start = end; +                    break;                  case internal::INVALID_LEAD:                      out = utf8::append (replacement, out);                      ++start; @@ -129,14 +129,28 @@ namespace utf8      template <typename octet_iterator, typename output_iterator>      inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)      { -        static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd); +        static const utfchar32_t replacement_marker = utf8::internal::mask16(0xfffd);          return utf8::replace_invalid(start, end, out, replacement_marker);      } +    inline std::string replace_invalid(const std::string& s, utfchar32_t replacement) +    { +        std::string result; +        replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); +        return result; +    } + +    inline std::string replace_invalid(const std::string& s) +    { +        std::string result; +        replace_invalid(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } +      template <typename octet_iterator> -    uint32_t next(octet_iterator& it, octet_iterator end) +    utfchar32_t next(octet_iterator& it, octet_iterator end)      { -        uint32_t cp = 0; +        utfchar32_t cp = 0;          internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);          switch (err_code) {              case internal::UTF8_OK : @@ -146,21 +160,31 @@ namespace utf8              case internal::INVALID_LEAD :              case internal::INCOMPLETE_SEQUENCE :              case internal::OVERLONG_SEQUENCE : -                throw invalid_utf8(*it); +                throw invalid_utf8(static_cast<utfchar8_t>(*it));              case internal::INVALID_CODE_POINT :                  throw invalid_code_point(cp);          }          return cp;      } +    template <typename word_iterator> +    utfchar32_t next16(word_iterator& it, word_iterator end) +    { +        utfchar32_t cp = 0; +        internal::utf_error err_code = utf8::internal::validate_next16(it, end, cp); +        if (err_code == internal::NOT_ENOUGH_ROOM) +            throw not_enough_room(); +        return cp; +    } +      template <typename octet_iterator> -    uint32_t peek_next(octet_iterator it, octet_iterator end) +    utfchar32_t peek_next(octet_iterator it, octet_iterator end)      {          return utf8::next(it, end);      }      template <typename octet_iterator> -    uint32_t prior(octet_iterator& it, octet_iterator start) +    utfchar32_t prior(octet_iterator& it, octet_iterator start)      {          // can't do much if it == start          if (it == start) @@ -174,23 +198,19 @@ namespace utf8          return utf8::peek_next(it, end);      } -    /// Deprecated in versions that include "prior" -    template <typename octet_iterator> -    uint32_t previous(octet_iterator& it, octet_iterator pass_start) -    { -        octet_iterator end = it; -        while (utf8::internal::is_trail(*(--it))) -            if (it == pass_start) -                throw invalid_utf8(*it); // error - no lead byte in the sequence -        octet_iterator temp = it; -        return utf8::next(temp, end); -    } -      template <typename octet_iterator, typename distance_type>      void advance (octet_iterator& it, distance_type n, octet_iterator end)      { -        for (distance_type i = 0; i < n; ++i) -            utf8::next(it, end); +        const distance_type zero(0); +        if (n < zero) { +            // backward +            for (distance_type i = n; i < zero; ++i) +                utf8::prior(it, end); +        } else { +            // forward +            for (distance_type i = zero; i < n; ++i) +                utf8::next(it, end); +        }      }      template <typename octet_iterator> @@ -207,23 +227,23 @@ namespace utf8      octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)      {          while (start != end) { -            uint32_t cp = utf8::internal::mask16(*start++); +            utfchar32_t cp = utf8::internal::mask16(*start++);              // Take care of surrogate pairs first              if (utf8::internal::is_lead_surrogate(cp)) {                  if (start != end) { -                    uint32_t trail_surrogate = utf8::internal::mask16(*start++); +                    const utfchar32_t trail_surrogate = utf8::internal::mask16(*start++);                      if (utf8::internal::is_trail_surrogate(trail_surrogate))                          cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;                      else -                        throw invalid_utf16(static_cast<uint16_t>(trail_surrogate)); +                        throw invalid_utf16(static_cast<utfchar16_t>(trail_surrogate));                  }                  else -                    throw invalid_utf16(static_cast<uint16_t>(cp)); +                    throw invalid_utf16(static_cast<utfchar16_t>(cp));              }              // Lone trail surrogate              else if (utf8::internal::is_trail_surrogate(cp)) -                throw invalid_utf16(static_cast<uint16_t>(cp)); +                throw invalid_utf16(static_cast<utfchar16_t>(cp));              result = utf8::append(cp, result);          } @@ -233,14 +253,14 @@ namespace utf8      template <typename u16bit_iterator, typename octet_iterator>      u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)      { -        while (start != end) { -            uint32_t cp = utf8::next(start, end); +        while (start < end) { +            const utfchar32_t cp = utf8::next(start, end);              if (cp > 0xffff) { //make a surrogate pair -                *result++ = static_cast<uint16_t>((cp >> 10)   + internal::LEAD_OFFSET); -                *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); +                *result++ = static_cast<utfchar16_t>((cp >> 10)   + internal::LEAD_OFFSET); +                *result++ = static_cast<utfchar16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);              }              else -                *result++ = static_cast<uint16_t>(cp); +                *result++ = static_cast<utfchar16_t>(cp);          }          return result;      } @@ -257,7 +277,7 @@ namespace utf8      template <typename octet_iterator, typename u32bit_iterator>      u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)      { -        while (start != end) +        while (start < end)              (*result++) = utf8::next(start, end);          return result; @@ -265,23 +285,28 @@ namespace utf8      // The iterator class      template <typename octet_iterator> -    class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> { +    class iterator {        octet_iterator it;        octet_iterator range_start;        octet_iterator range_end;        public: +      typedef utfchar32_t value_type; +      typedef utfchar32_t* pointer; +      typedef utfchar32_t& reference; +      typedef std::ptrdiff_t difference_type; +      typedef std::bidirectional_iterator_tag iterator_category;        iterator () {}        explicit iterator (const octet_iterator& octet_it, -                         const octet_iterator& range_start, -                         const octet_iterator& range_end) : -               it(octet_it), range_start(range_start), range_end(range_end) +                         const octet_iterator& rangestart, +                         const octet_iterator& rangeend) : +               it(octet_it), range_start(rangestart), range_end(rangeend)        {            if (it < range_start || it > range_end)                throw std::out_of_range("Invalid utf-8 iterator position");        }        // the default "big three" are OK        octet_iterator base () const { return it; } -      uint32_t operator * () const +      utfchar32_t operator * () const        {            octet_iterator temp = it;            return utf8::next(temp, range_end); @@ -322,6 +347,13 @@ namespace utf8  } // namespace utf8 -#endif //header guard +#if UTF_CPP_CPLUSPLUS >= 202002L // C++ 20 or later +#include "cpp20.h" +#elif UTF_CPP_CPLUSPLUS >= 201703L // C++ 17 or later +#include "cpp17.h" +#elif UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later +#include "cpp11.h" +#endif // C++ 11 or later +#endif //header guard diff --git a/lib/charset/utf8/core.h b/lib/charset/utf8/core.h index 693d388..4494c53 100644 --- a/lib/charset/utf8/core.h +++ b/lib/charset/utf8/core.h @@ -29,15 +29,42 @@ DEALINGS IN THE SOFTWARE.  #define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731  #include <iterator> +#include <cstring> +#include <string> + +// Determine the C++ standard version. +// If the user defines UTF_CPP_CPLUSPLUS, use that. +// Otherwise, trust the unreliable predefined macro __cplusplus + +#if !defined UTF_CPP_CPLUSPLUS +    #define UTF_CPP_CPLUSPLUS __cplusplus +#endif + +#if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later +    #define UTF_CPP_OVERRIDE override +    #define UTF_CPP_NOEXCEPT noexcept +#else // C++ 98/03 +    #define UTF_CPP_OVERRIDE +    #define UTF_CPP_NOEXCEPT throw() +#endif // C++ 11 or later +  namespace utf8  { -    // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers -    // You may need to change them to match your system. -    // These typedefs have the same names as ones from cstdint, or boost/cstdint -    typedef unsigned char   uint8_t; -    typedef unsigned short  uint16_t; -    typedef unsigned int    uint32_t; +// The typedefs for 8-bit, 16-bit and 32-bit code units +#if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later +    #if UTF_CPP_CPLUSPLUS >= 202002L // C++ 20 or later +        typedef char8_t         utfchar8_t; +    #else // C++ 11/14/17 +        typedef unsigned char   utfchar8_t; +    #endif +    typedef char16_t        utfchar16_t; +    typedef char32_t        utfchar32_t; +#else // C++ 98/03 +    typedef unsigned char   utfchar8_t; +    typedef unsigned short  utfchar16_t; +    typedef unsigned int    utfchar32_t; +#endif // C++ 11 or later  // Helper code - not intended to be directly called by the library users. May be changed at any time  namespace internal @@ -45,61 +72,62 @@ namespace internal      // Unicode constants      // Leading (high) surrogates: 0xd800 - 0xdbff      // Trailing (low) surrogates: 0xdc00 - 0xdfff -    const uint16_t LEAD_SURROGATE_MIN  = 0xd800u; -    const uint16_t LEAD_SURROGATE_MAX  = 0xdbffu; -    const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; -    const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; -    const uint16_t LEAD_OFFSET         = LEAD_SURROGATE_MIN - (0x10000 >> 10); -    const uint32_t SURROGATE_OFFSET    = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; +    const utfchar16_t LEAD_SURROGATE_MIN  = 0xd800u; +    const utfchar16_t LEAD_SURROGATE_MAX  = 0xdbffu; +    const utfchar16_t TRAIL_SURROGATE_MIN = 0xdc00u; +    const utfchar16_t TRAIL_SURROGATE_MAX = 0xdfffu; +    const utfchar16_t LEAD_OFFSET         = 0xd7c0u;       // LEAD_SURROGATE_MIN - (0x10000 >> 10) +    const utfchar32_t SURROGATE_OFFSET    = 0xfca02400u;   // 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN      // Maximum valid value for a Unicode code point -    const uint32_t CODE_POINT_MAX      = 0x0010ffffu; +    const utfchar32_t CODE_POINT_MAX      = 0x0010ffffu;      template<typename octet_type> -    inline uint8_t mask8(octet_type oc) +    inline utfchar8_t mask8(octet_type oc)      { -        return static_cast<uint8_t>(0xff & oc); +        return static_cast<utfchar8_t>(0xff & oc);      }      template<typename u16_type> -    inline uint16_t mask16(u16_type oc) +    inline utfchar16_t mask16(u16_type oc)      { -        return static_cast<uint16_t>(0xffff & oc); +        return static_cast<utfchar16_t>(0xffff & oc);      } +      template<typename octet_type>      inline bool is_trail(octet_type oc)      {          return ((utf8::internal::mask8(oc) >> 6) == 0x2);      } -    template <typename u16> -    inline bool is_lead_surrogate(u16 cp) +    inline bool is_lead_surrogate(utfchar32_t cp)      {          return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);      } -    template <typename u16> -    inline bool is_trail_surrogate(u16 cp) +    inline bool is_trail_surrogate(utfchar32_t cp)      {          return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);      } -    template <typename u16> -    inline bool is_surrogate(u16 cp) +    inline bool is_surrogate(utfchar32_t cp)      {          return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);      } -    template <typename u32> -    inline bool is_code_point_valid(u32 cp) +    inline bool is_code_point_valid(utfchar32_t cp)      {          return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));      } +    inline bool is_in_bmp(utfchar32_t cp) +    { +        return cp < utfchar32_t(0x10000); +    } +      template <typename octet_iterator> -    inline typename std::iterator_traits<octet_iterator>::difference_type -    sequence_length(octet_iterator lead_it) +    int sequence_length(octet_iterator lead_it)      { -        uint8_t lead = utf8::internal::mask8(*lead_it); +        const utfchar8_t lead = utf8::internal::mask8(*lead_it);          if (lead < 0x80)              return 1;          else if ((lead >> 5) == 0x6) @@ -112,8 +140,7 @@ namespace internal              return 0;      } -    template <typename octet_difference_type> -    inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) +    inline bool is_overlong_sequence(utfchar32_t cp, int length)      {          if (cp < 0x80) {              if (length != 1)  @@ -127,7 +154,6 @@ namespace internal              if (length != 3)                   return true;          } -          return false;      } @@ -135,22 +161,22 @@ namespace internal      /// Helper for get_sequence_x      template <typename octet_iterator> -    utf_error increase_safely(octet_iterator& it, octet_iterator end) +    utf_error increase_safely(octet_iterator& it, const octet_iterator end)      {          if (++it == end)              return NOT_ENOUGH_ROOM;          if (!utf8::internal::is_trail(*it))              return INCOMPLETE_SEQUENCE; -         +          return UTF8_OK;      } -    #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}     +    #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}      /// get_sequence_x functions decode utf-8 sequences of the length x      template <typename octet_iterator> -    utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point) +    utf_error get_sequence_1(octet_iterator& it, octet_iterator end, utfchar32_t& code_point)      {          if (it == end)              return NOT_ENOUGH_ROOM; @@ -161,11 +187,11 @@ namespace internal      }      template <typename octet_iterator> -    utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point) +    utf_error get_sequence_2(octet_iterator& it, octet_iterator end, utfchar32_t& code_point)      {          if (it == end)               return NOT_ENOUGH_ROOM; -         +          code_point = utf8::internal::mask8(*it);          UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) @@ -176,7 +202,7 @@ namespace internal      }      template <typename octet_iterator> -    utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point) +    utf_error get_sequence_3(octet_iterator& it, octet_iterator end, utfchar32_t& code_point)      {          if (it == end)              return NOT_ENOUGH_ROOM; @@ -195,7 +221,7 @@ namespace internal      }      template <typename octet_iterator> -    utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point) +    utf_error get_sequence_4(octet_iterator& it, octet_iterator end, utfchar32_t& code_point)      {          if (it == end)             return NOT_ENOUGH_ROOM; @@ -220,21 +246,23 @@ namespace internal      #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR      template <typename octet_iterator> -    utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point) +    utf_error validate_next(octet_iterator& it, octet_iterator end, utfchar32_t& code_point)      { +        if (it == end) +            return NOT_ENOUGH_ROOM; +          // Save the original value of it so we can go back in case of failure          // Of course, it does not make much sense with i.e. stream iterators          octet_iterator original_it = it; -        uint32_t cp = 0; +        utfchar32_t cp = 0;          // Determine the sequence length based on the lead octet -        typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type; -        const octet_difference_type length = utf8::internal::sequence_length(it); +        const int length = utf8::internal::sequence_length(it);          // Get trail octets and calculate the code point          utf_error err = UTF8_OK;          switch (length) { -            case 0:  +            case 0:                  return INVALID_LEAD;              case 1:                  err = utf8::internal::get_sequence_1(it, end, cp); @@ -273,16 +301,133 @@ namespace internal      template <typename octet_iterator>      inline utf_error validate_next(octet_iterator& it, octet_iterator end) { -        uint32_t ignored; +        utfchar32_t ignored;          return utf8::internal::validate_next(it, end, ignored);      } +    template <typename word_iterator> +    utf_error validate_next16(word_iterator& it, word_iterator end, utfchar32_t& code_point) +    { +        if (it == end) +            return NOT_ENOUGH_ROOM; +        // Save the original value of it so we can go back in case of failure +        // Of course, it does not make much sense with i.e. stream iterators +        word_iterator original_it = it; + +        utf_error err = UTF8_OK; + +        const utfchar16_t first_word = *it++; +        if (!is_surrogate(first_word)) { +            code_point = first_word; +            return UTF8_OK; +        } +        else { +            if (it == end) +                err = NOT_ENOUGH_ROOM; +            else if (is_lead_surrogate(first_word)) { +                const utfchar16_t second_word = *it++; +                if (is_trail_surrogate(second_word)) { +                    code_point = (first_word << 10) + second_word + SURROGATE_OFFSET; +                    return UTF8_OK; +                } else  +                    err = INCOMPLETE_SEQUENCE;  +                 +            } else { +                err = INVALID_LEAD;                +            } +        } +        // error branch +        it = original_it; +        return err; +    } + +    // Internal implementation of both checked and unchecked append() function +    // This function will be invoked by the overloads below, as they will know +    // the octet_type. +    template <typename octet_iterator, typename octet_type> +    octet_iterator append(utfchar32_t cp, octet_iterator result) { +        if (cp < 0x80)                        // one octet +            *(result++) = static_cast<octet_type>(cp); +        else if (cp < 0x800) {                // two octets +            *(result++) = static_cast<octet_type>((cp >> 6)          | 0xc0); +            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80); +        } +        else if (cp < 0x10000) {              // three octets +            *(result++) = static_cast<octet_type>((cp >> 12)         | 0xe0); +            *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80); +            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80); +        } +        else {                                // four octets +            *(result++) = static_cast<octet_type>((cp >> 18)         | 0xf0); +            *(result++) = static_cast<octet_type>(((cp >> 12) & 0x3f)| 0x80); +            *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80); +            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80); +        } +        return result; +    } +     +    // One of the following overloads will be invoked from the API calls + +    // A simple (but dangerous) case: the caller appends byte(s) to a char array +    inline char* append(utfchar32_t cp, char* result) { +        return append<char*, char>(cp, result); +    } + +    // Hopefully, most common case: the caller uses back_inserter +    // i.e. append(cp, std::back_inserter(str)); +    template<typename container_type> +    std::back_insert_iterator<container_type> append +            (utfchar32_t cp, std::back_insert_iterator<container_type> result) { +        return append<std::back_insert_iterator<container_type>, +            typename container_type::value_type>(cp, result); +    } + +    // The caller uses some other kind of output operator - not covered above +    // Note that in this case we are not able to determine octet_type +    // so we assume it's utfchar8_t; that can cause a conversion warning if we are wrong. +    template <typename octet_iterator> +    octet_iterator append(utfchar32_t cp, octet_iterator result) { +        return append<octet_iterator, utfchar8_t>(cp, result); +    } + +    // Internal implementation of both checked and unchecked append16() function +    // This function will be invoked by the overloads below, as they will know +    // the word_type. +    template <typename word_iterator, typename word_type> +    word_iterator append16(utfchar32_t cp, word_iterator result) { +        if (is_in_bmp(cp)) +            *(result++) = static_cast<word_type>(cp); +        else { +            // Code points from the supplementary planes are encoded via surrogate pairs +            *(result++) = static_cast<word_type>(LEAD_OFFSET + (cp >> 10)); +            *(result++) = static_cast<word_type>(TRAIL_SURROGATE_MIN + (cp & 0x3FF)); +        } +        return result; +    } + +    // Hopefully, most common case: the caller uses back_inserter +    // i.e. append16(cp, std::back_inserter(str)); +    template<typename container_type> +    std::back_insert_iterator<container_type> append16 +            (utfchar32_t cp, std::back_insert_iterator<container_type> result) { +        return append16<std::back_insert_iterator<container_type>, +            typename container_type::value_type>(cp, result); +    } + +    // The caller uses some other kind of output operator - not covered above +    // Note that in this case we are not able to determine word_type +    // so we assume it's utfchar16_t; that can cause a conversion warning if we are wrong. +    template <typename word_iterator> +    word_iterator append16(utfchar32_t cp, word_iterator result) { +        return append16<word_iterator, utfchar16_t>(cp, result); +    } +  } // namespace internal      /// The library API - functions intended to be called by the users      // Byte order mark -    const uint8_t bom[] = {0xef, 0xbb, 0xbf}; +    const utfchar8_t bom[] = {0xef, 0xbb, 0xbf};      template <typename octet_iterator>      octet_iterator find_invalid(octet_iterator start, octet_iterator end) @@ -296,12 +441,36 @@ namespace internal          return result;      } +    inline const char* find_invalid(const char* str) +    { +        const char* end = str + std::strlen(str); +        return find_invalid(str, end);  +    } + +    inline std::size_t find_invalid(const std::string& s) +    { +        std::string::const_iterator invalid = find_invalid(s.begin(), s.end()); +        return (invalid == s.end()) ? std::string::npos : static_cast<std::size_t>(invalid - s.begin()); +    } +      template <typename octet_iterator>      inline bool is_valid(octet_iterator start, octet_iterator end)      {          return (utf8::find_invalid(start, end) == end);      } +    inline bool is_valid(const char* str) +    { +        return (*(utf8::find_invalid(str)) == '\0'); +    } + +    inline bool is_valid(const std::string& s) +    { +        return is_valid(s.begin(), s.end()); +    } + + +      template <typename octet_iterator>      inline bool starts_with_bom (octet_iterator it, octet_iterator end)      { @@ -311,17 +480,11 @@ namespace internal              ((it != end) && (utf8::internal::mask8(*it))   == bom[2])             );      } -	 -    //Deprecated in release 2.3  -    template <typename octet_iterator> -    inline bool is_bom (octet_iterator it) + +    inline bool starts_with_bom(const std::string& s)      { -        return ( -            (utf8::internal::mask8(*it++)) == bom[0] && -            (utf8::internal::mask8(*it++)) == bom[1] && -            (utf8::internal::mask8(*it))   == bom[2] -           ); -    } +        return starts_with_bom(s.begin(), s.end()); +    }   } // namespace utf8  #endif // header guard diff --git a/lib/charset/utf8/cpp11.h b/lib/charset/utf8/cpp11.h new file mode 100644 index 0000000..691633c --- /dev/null +++ b/lib/charset/utf8/cpp11.h @@ -0,0 +1,70 @@ +// Copyright 2018 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1 +#define UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1 + +#include "checked.h" + +namespace utf8 +{ +    inline void append16(utfchar32_t cp, std::u16string& s) +    { +        append16(cp, std::back_inserter(s)); +    } + +    inline std::string utf16to8(const std::u16string& s) +    { +        std::string result; +        utf16to8(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::u16string utf8to16(const std::string& s) +    { +        std::u16string result; +        utf8to16(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::string utf32to8(const std::u32string& s) +    { +        std::string result; +        utf32to8(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::u32string utf8to32(const std::string& s) +    { +        std::u32string result; +        utf8to32(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } +} // namespace utf8 + +#endif // header guard + diff --git a/lib/charset/utf8/cpp17.h b/lib/charset/utf8/cpp17.h new file mode 100644 index 0000000..6e2fcc2 --- /dev/null +++ b/lib/charset/utf8/cpp17.h @@ -0,0 +1,96 @@ +// Copyright 2018 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9 +#define UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9 + +#include "cpp11.h" + +namespace utf8 +{ +    inline std::string utf16to8(std::u16string_view s) +    { +        std::string result; +        utf16to8(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::u16string utf8to16(std::string_view s) +    { +        std::u16string result; +        utf8to16(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::string utf32to8(std::u32string_view s) +    { +        std::string result; +        utf32to8(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::u32string utf8to32(std::string_view s) +    { +        std::u32string result; +        utf8to32(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::size_t find_invalid(std::string_view s) +    { +        std::string_view::const_iterator invalid = find_invalid(s.begin(), s.end()); +        return (invalid == s.end()) ? std::string_view::npos : static_cast<std::size_t>(invalid - s.begin()); +    } + +    inline bool is_valid(std::string_view s) +    { +        return is_valid(s.begin(), s.end()); +    } + +    inline std::string replace_invalid(std::string_view s, char32_t replacement) +    { +        std::string result; +        replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); +        return result; +    } + +    inline std::string replace_invalid(std::string_view s) +    { +        std::string result; +        replace_invalid(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline bool starts_with_bom(std::string_view s) +    { +        return starts_with_bom(s.begin(), s.end()); +    } +  +} // namespace utf8 + +#endif // header guard + diff --git a/lib/charset/utf8/cpp20.h b/lib/charset/utf8/cpp20.h new file mode 100644 index 0000000..07b61d0 --- /dev/null +++ b/lib/charset/utf8/cpp20.h @@ -0,0 +1,124 @@ +// Copyright 2022 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_207e906c01_03a3_4daf_b420_ea7ea952b3c9 +#define UTF8_FOR_CPP_207e906c01_03a3_4daf_b420_ea7ea952b3c9 + +#include "cpp17.h" + +namespace utf8 +{ +    inline std::u8string utf16tou8(const std::u16string& s) +    { +        std::u8string result; +        utf16to8(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::u8string utf16tou8(std::u16string_view s) +    { +        std::u8string result; +        utf16to8(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::u16string utf8to16(const std::u8string& s) +    { +        std::u16string result; +        utf8to16(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::u16string utf8to16(const std::u8string_view& s) +    { +        std::u16string result; +        utf8to16(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::u8string utf32tou8(const std::u32string& s) +    { +        std::u8string result; +        utf32to8(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::u8string utf32tou8(const std::u32string_view& s) +    { +        std::u8string result; +        utf32to8(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::u32string utf8to32(const std::u8string& s) +    { +        std::u32string result; +        utf8to32(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::u32string utf8to32(const std::u8string_view& s) +    { +        std::u32string result; +        utf8to32(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline std::size_t find_invalid(const std::u8string& s) +    { +        std::u8string::const_iterator invalid = find_invalid(s.begin(), s.end()); +        return (invalid == s.end()) ? std::string_view::npos : static_cast<std::size_t>(invalid - s.begin()); +    } + +    inline bool is_valid(const std::u8string& s) +    { +        return is_valid(s.begin(), s.end()); +    } + +    inline std::u8string replace_invalid(const std::u8string& s, char32_t replacement) +    { +        std::u8string result; +        replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); +        return result; +    } + +    inline std::u8string replace_invalid(const std::u8string& s) +    { +        std::u8string result; +        replace_invalid(s.begin(), s.end(), std::back_inserter(result)); +        return result; +    } + +    inline bool starts_with_bom(const std::u8string& s) +    { +        return starts_with_bom(s.begin(), s.end()); +    } +  +} // namespace utf8 + +#endif // header guard + diff --git a/lib/charset/utf8/unchecked.h b/lib/charset/utf8/unchecked.h index cb24271..65d4948 100644 --- a/lib/charset/utf8/unchecked.h +++ b/lib/charset/utf8/unchecked.h @@ -32,37 +32,79 @@ DEALINGS IN THE SOFTWARE.  namespace utf8  { -    namespace unchecked  +    namespace unchecked      {          template <typename octet_iterator> -        octet_iterator append(uint32_t cp, octet_iterator result) +        octet_iterator append(utfchar32_t cp, octet_iterator result)          { -            if (cp < 0x80)                        // one octet -                *(result++) = static_cast<uint8_t>(cp);   -            else if (cp < 0x800) {                // two octets -                *(result++) = static_cast<uint8_t>((cp >> 6)          | 0xc0); -                *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80); -            } -            else if (cp < 0x10000) {              // three octets -                *(result++) = static_cast<uint8_t>((cp >> 12)         | 0xe0); -                *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80); -                *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80); -            } -            else {                                // four octets -                *(result++) = static_cast<uint8_t>((cp >> 18)         | 0xf0); -                *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80); -                *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80); -                *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80); +            return internal::append(cp, result); +        } + +        template <typename word_iterator> +        word_iterator append16(utfchar32_t cp, word_iterator result) +        { +            return internal::append16(cp, result); +        } + +        template <typename octet_iterator, typename output_iterator> +        output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, utfchar32_t replacement) +        { +            while (start != end) { +                octet_iterator sequence_start = start; +                internal::utf_error err_code = utf8::internal::validate_next(start, end); +                switch (err_code) { +                    case internal::UTF8_OK : +                        for (octet_iterator it = sequence_start; it != start; ++it) +                            *out++ = *it; +                        break; +                    case internal::NOT_ENOUGH_ROOM: +                        out = utf8::unchecked::append(replacement, out); +                        start = end; +                        break; +                    case internal::INVALID_LEAD: +                        out = utf8::unchecked::append(replacement, out); +                        ++start; +                        break; +                    case internal::INCOMPLETE_SEQUENCE: +                    case internal::OVERLONG_SEQUENCE: +                    case internal::INVALID_CODE_POINT: +                        out = utf8::unchecked::append(replacement, out); +                        ++start; +                        // just one replacement mark for the sequence +                        while (start != end && utf8::internal::is_trail(*start)) +                            ++start; +                        break; +                }              } +            return out; +        } + +        template <typename octet_iterator, typename output_iterator> +        inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) +        { +            static const utfchar32_t replacement_marker = utf8::internal::mask16(0xfffd); +            return utf8::unchecked::replace_invalid(start, end, out, replacement_marker); +        } + +        inline std::string replace_invalid(const std::string& s, utfchar32_t replacement) +        { +            std::string result; +            replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); +            return result; +        } + +        inline std::string replace_invalid(const std::string& s) +        { +            std::string result; +            replace_invalid(s.begin(), s.end(), std::back_inserter(result));              return result;          }          template <typename octet_iterator> -        uint32_t next(octet_iterator& it) +        utfchar32_t next(octet_iterator& it)          { -            uint32_t cp = utf8::internal::mask8(*it); -            typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it); -            switch (length) { +            utfchar32_t cp = utf8::internal::mask8(*it); +            switch (utf8::internal::sequence_length(it)) {                  case 1:                      break;                  case 2: @@ -85,40 +127,50 @@ namespace utf8                      break;              }              ++it; -            return cp;         +            return cp;          }          template <typename octet_iterator> -        uint32_t peek_next(octet_iterator it) +        utfchar32_t peek_next(octet_iterator it)          { -            return utf8::unchecked::next(it);     +            return utf8::unchecked::next(it);          } -        template <typename octet_iterator> -        uint32_t prior(octet_iterator& it) +        template <typename word_iterator> +        utfchar32_t next16(word_iterator& it)          { -            while (utf8::internal::is_trail(*(--it))) ; -            octet_iterator temp = it; -            return utf8::unchecked::next(temp); +            utfchar32_t cp = utf8::internal::mask16(*it++); +            if (utf8::internal::is_lead_surrogate(cp)) +                return (cp << 10) + *it++ + utf8::internal::SURROGATE_OFFSET; +            return cp;          } -        // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)          template <typename octet_iterator> -        inline uint32_t previous(octet_iterator& it) +        utfchar32_t prior(octet_iterator& it)          { -            return utf8::unchecked::prior(it); +            while (utf8::internal::is_trail(*(--it))) ; +            octet_iterator temp = it; +            return utf8::unchecked::next(temp);          }          template <typename octet_iterator, typename distance_type> -        void advance (octet_iterator& it, distance_type n) +        void advance(octet_iterator& it, distance_type n)          { -            for (distance_type i = 0; i < n; ++i) -                utf8::unchecked::next(it); +            const distance_type zero(0); +            if (n < zero) { +                // backward +                for (distance_type i = n; i < zero; ++i) +                    utf8::unchecked::prior(it); +            } else { +                // forward +                for (distance_type i = zero; i < n; ++i) +                    utf8::unchecked::next(it); +            }          }          template <typename octet_iterator>          typename std::iterator_traits<octet_iterator>::difference_type -        distance (octet_iterator first, octet_iterator last) +        distance(octet_iterator first, octet_iterator last)          {              typename std::iterator_traits<octet_iterator>::difference_type dist;              for (dist = 0; first < last; ++dist)  @@ -127,37 +179,39 @@ namespace utf8          }          template <typename u16bit_iterator, typename octet_iterator> -        octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) -        {        +        octet_iterator utf16to8(u16bit_iterator start, u16bit_iterator end, octet_iterator result) +        {              while (start != end) { -                uint32_t cp = utf8::internal::mask16(*start++); -            // Take care of surrogate pairs first +                utfchar32_t cp = utf8::internal::mask16(*start++); +                // Take care of surrogate pairs first                  if (utf8::internal::is_lead_surrogate(cp)) { -                    uint32_t trail_surrogate = utf8::internal::mask16(*start++); +                    if (start == end) +                        return result; +                    utfchar32_t trail_surrogate = utf8::internal::mask16(*start++);                      cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;                  }                  result = utf8::unchecked::append(cp, result);              } -            return result;          +            return result;          }          template <typename u16bit_iterator, typename octet_iterator> -        u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) +        u16bit_iterator utf8to16(octet_iterator start, octet_iterator end, u16bit_iterator result)          {              while (start < end) { -                uint32_t cp = utf8::unchecked::next(start); +                utfchar32_t cp = utf8::unchecked::next(start);                  if (cp > 0xffff) { //make a surrogate pair -                    *result++ = static_cast<uint16_t>((cp >> 10)   + internal::LEAD_OFFSET); -                    *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); +                    *result++ = static_cast<utfchar16_t>((cp >> 10)   + internal::LEAD_OFFSET); +                    *result++ = static_cast<utfchar16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);                  }                  else -                    *result++ = static_cast<uint16_t>(cp); +                    *result++ = static_cast<utfchar16_t>(cp);              }              return result;          }          template <typename octet_iterator, typename u32bit_iterator> -        octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) +        octet_iterator utf32to8(u32bit_iterator start, u32bit_iterator end, octet_iterator result)          {              while (start != end)                  result = utf8::unchecked::append(*(start++), result); @@ -166,7 +220,7 @@ namespace utf8          }          template <typename octet_iterator, typename u32bit_iterator> -        u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) +        u32bit_iterator utf8to32(octet_iterator start, octet_iterator end, u32bit_iterator result)          {              while (start < end)                  (*result++) = utf8::unchecked::next(start); @@ -176,14 +230,19 @@ namespace utf8          // The iterator class          template <typename octet_iterator> -          class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {  +          class iterator {              octet_iterator it;              public: +            typedef utfchar32_t value_type; +            typedef utfchar32_t* pointer; +            typedef utfchar32_t& reference; +            typedef std::ptrdiff_t difference_type; +            typedef std::bidirectional_iterator_tag iterator_category;              iterator () {}              explicit iterator (const octet_iterator& octet_it): it(octet_it) {}              // the default "big three" are OK              octet_iterator base () const { return it; } -            uint32_t operator * () const +            utfchar32_t operator * () const              {                  octet_iterator temp = it;                  return utf8::unchecked::next(temp); | 
