Utf8Codex.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. #ifdef _WIN32
  7. #include <windows.h>
  8. #include <wtypes.h>
  9. #else
  10. // TODO: Abstract out into it's own file
  11. #include "pal.h"
  12. #include "inc/rt/palrt.h"
  13. #include <stdint.h>
  14. #endif
  15. // Utf8Codex.h needs to be self contained, so these type defs are duplicated from CommonTypeDefs.h
  16. #ifdef _WIN32
  17. typedef WCHAR char16;
  18. #define _u(s) L##s
  19. #else
  20. typedef char16_t char16;
  21. #define _u(s) u##s
  22. #endif
  23. typedef char16 wchar;
  24. #ifndef Unused
  25. #define Unused(var) var
  26. #endif
  27. #ifndef _WIN32
  28. // Templates are defined here in order to avoid a dependency on C++
  29. // <type_traits> header file,
  30. // or on compiler-specific contructs.
  31. extern "C++" {
  32. template <size_t S>
  33. struct _ENUM_FLAG_INTEGER_FOR_SIZE;
  34. template <>
  35. struct _ENUM_FLAG_INTEGER_FOR_SIZE<1>
  36. {
  37. typedef int8_t type;
  38. };
  39. template <>
  40. struct _ENUM_FLAG_INTEGER_FOR_SIZE<2>
  41. {
  42. typedef int16_t type;
  43. };
  44. template <>
  45. struct _ENUM_FLAG_INTEGER_FOR_SIZE<4>
  46. {
  47. typedef int32_t type;
  48. };
  49. // used as an approximation of std::underlying_type<T>
  50. template <class T>
  51. struct _ENUM_FLAG_SIZED_INTEGER
  52. {
  53. typedef typename _ENUM_FLAG_INTEGER_FOR_SIZE<sizeof(T)>::type
  54. type;
  55. };
  56. }
  57. #define DEFINE_ENUM_FLAG_OPERATORS(ENUMTYPE) \
  58. extern "C++" { \
  59. inline ENUMTYPE operator | (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) | ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
  60. inline ENUMTYPE &operator |= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type &)a) |= ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
  61. inline ENUMTYPE operator & (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) & ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
  62. inline ENUMTYPE &operator &= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type &)a) &= ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
  63. inline ENUMTYPE operator ~ (ENUMTYPE a) { return ENUMTYPE(~((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a)); } \
  64. inline ENUMTYPE operator ^ (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) ^ ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
  65. inline ENUMTYPE &operator ^= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type &)a) ^= ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
  66. }
  67. #endif
  68. typedef unsigned __int32 uint32;
  69. // charcount_t represents a count of characters in a String
  70. // It is unsigned and the maximum value is (INT_MAX-1)
  71. typedef uint32 charcount_t;
  72. typedef BYTE utf8char_t;
  73. typedef const utf8char_t CUTF8;
  74. typedef utf8char_t* LPUTF8;
  75. typedef const utf8char_t *LPCUTF8;
  76. // Unicode 4.0, unknown char should be converted to replace mark, U+FFFD.
  77. #define UNICODE_UNKNOWN_CHAR_MARK 0xFFFD
  78. #define UNICODE_TCHAR_UKNOWN_CHAR_MARK _T('\xFFFD')
  79. namespace utf8
  80. {
  81. // Terminology -
  82. // Code point - A ordinal value mapped to a standard ideograph as defined by ISO/IEC 10646-1. Here
  83. // also referred to as a UCS code point but can also be often be referred to as a UNICODE
  84. // code point.
  85. // UTF-8 - An encoding of UCS code points as defined by RFC-3629.
  86. // UTF-16 - An encoding of UCS code points as defined by RFC-2781. Use as a synonym for UNICODE or
  87. // UCS-2. This is technically incorrect but usually harmless. This file assumes char16 *
  88. // maps to an UTF-16LE (little-endian) encoded sequence of words.
  89. // Unit - The unit of encoding. For UTF-8 it is a byte (octet). For UTF-16 it is a word (two octets).
  90. // Valid - A UTF-8 byte sequence conforming to RFC-3629.
  91. // Well-formed - A sequence of bytes that conform to the encoding pattern of UTF8 but might be too long or
  92. // otherwise invalid. For example C0 80 is a well-formed but invalid encoding of U+0000.
  93. // Start byte - A byte can start a well-formed UTF-8 sequence.
  94. // Lead byte - A byte can start a well-formed multi-unit sequence but not a single byte sequence.
  95. // Trail byte - A byte that can appear after a lead-byte in a well-formed multi-unit sequence.
  96. // Surrogate pair - A UTF-16 word pair to encode characters outside the Unicode base plain as defined by
  97. // RFC-2781. Two char16 values are used to encode one UCS code point.
  98. // character index - The index into a UTF-16 sequence.
  99. // byte index - The index into a UTF-8 sequence.
  100. // Return the number of bytes needed to encode the given character (ignoring surrogate pairs)
  101. inline size_t EncodedSize(char16 ch)
  102. {
  103. if (ch < 0x0080) return 1;
  104. if (ch < 0x0800) return 2;
  105. return 3;
  106. }
  107. enum DecodeOptions
  108. {
  109. doDefault = 0x00,
  110. doAllowThreeByteSurrogates = 0x01, // Allow invalid 3 byte encodings as would be encoded by CSEU-8
  111. doChunkedEncoding = 0x02, // For sequences at the end of a buffer do not advance into incomplete sequences
  112. // If incomplete UTF-8 sequence is encountered at the end of a buffer, this
  113. // option will cause Decode() to not advance the ptr value and DecodeTail to
  114. // move the pointer back one position so it again points to where c1 was read by
  115. // Decode(). In effect, incomplete sequences are treated as if end pointed to the
  116. // beginning incomplete sequence instead of in the middle of it.
  117. doSecondSurrogatePair = 0x04, // A previous call to DecodeTail returned the first word of a UTF-16
  118. // surrogate pair. The second call will return the second word and reset
  119. // this 'option'.
  120. doAllowInvalidWCHARs = 0x08, // Don't replace invalid wide chars with 0xFFFD
  121. };
  122. DEFINE_ENUM_FLAG_OPERATORS(DecodeOptions);
  123. // Decode the trail bytes after the UTF8 lead byte c1 but returning 0xFFFD if trail bytes are expected after end.
  124. _At_(ptr, _In_reads_(end - ptr) _Post_satisfies_(ptr >= _Old_(ptr) - 1 && ptr <= end))
  125. char16 DecodeTail(char16 c1, LPCUTF8& ptr, LPCUTF8 end, DecodeOptions& options);
  126. // Decode the UTF8 sequence into a UTF16 encoding. Code points outside the Unicode base plain will generate
  127. // surrogate pairs, using the 'doSecondSurrogatePair' option to remember the first word has already been returned.
  128. // If ptr == end 0x0000 is emitted. If ptr < end but the lead byte of the UTF8 sequence
  129. // expects trail bytes past end then 0xFFFD are emitted until ptr == end.
  130. _At_(ptr, _In_reads_(end - ptr) _Post_satisfies_(ptr >= _Old_(ptr) && ptr <= end))
  131. inline char16 Decode(LPCUTF8& ptr, LPCUTF8 end, DecodeOptions& options)
  132. {
  133. if (ptr >= end) return 0;
  134. utf8char_t c1 = *ptr++;
  135. if (c1 < 0x80) return static_cast<char16>(c1);
  136. return DecodeTail(c1, ptr, end, options);
  137. }
  138. // Encode ch into a UTF8 sequence ignoring surrogate pairs (which are encoded as two
  139. // separate code points). Use Encode() instead of EncodeFull() directly because it
  140. // special cases ASCII to avoid a call the most common characters.
  141. LPUTF8 EncodeFull(char16 ch, __out_ecount(3) LPUTF8 ptr);
  142. // Encode a surrogate pair into a utf8 sequence
  143. LPUTF8 EncodeSurrogatePair(char16 surrogateHigh, char16 surrogateLow, __out_ecount(4) LPUTF8 ptr);
  144. // Encode ch into a UTF8 sequence ignoring surrogate pairs (which are encoded as two
  145. // separate code points).
  146. inline LPUTF8 Encode(char16 ch, __out_ecount(3) LPUTF8 ptr)
  147. {
  148. if (ch < 0x80)
  149. {
  150. *ptr = static_cast<utf8char_t>(ch);
  151. return ptr + 1;
  152. }
  153. return EncodeFull(ch, ptr);
  154. }
  155. // Encode ch into a UTF8 sequence while being aware of surrogate pairs.
  156. inline LPUTF8 EncodeTrueUtf8(char16 ch, const char16** source, charcount_t* cch, __out_ecount((*cch + 1) * 3) LPUTF8 ptr)
  157. {
  158. if (ch < 0x80)
  159. {
  160. *ptr = static_cast<utf8char_t>(ch);
  161. return ptr + 1;
  162. }
  163. else if (ch < 0xD800 || (ch >= 0xE000 && ch <= 0xFFFF))
  164. {
  165. return EncodeFull(ch, ptr);
  166. }
  167. // We're now decoding a surrogate pair. If the input is malformed (eg. low surrogate is absent)
  168. // we'll instead encode the unicode replacement character as utf8
  169. if (*cch > 0)
  170. {
  171. char16 surrogateHigh = ch;
  172. char16 surrogateLow = **source;
  173. // Validate that the surrogate code units are within the appropriate
  174. // ranges for high and low surrogates
  175. if ((surrogateHigh >= 0xD800 && surrogateHigh <= 0xDBFF) &&
  176. (surrogateLow >= 0xDC00 && surrogateLow <= 0xDFFF))
  177. {
  178. LPUTF8 retptr = EncodeSurrogatePair(surrogateHigh, surrogateLow, ptr);
  179. // SAL analysis gets confused if we call EncodeSurrogatePair after
  180. // modifying cch
  181. // Consume the low surrogate
  182. *source = *source + 1;
  183. *cch = *cch - 1;
  184. return retptr;
  185. }
  186. }
  187. // Invalid input: insert the unicode replacement character instead
  188. ptr[0] = 0xEF;
  189. ptr[1] = 0xBF;
  190. ptr[2] = 0xBD;
  191. return ptr + 3;
  192. }
  193. // Return true if ch is a lead byte of a UTF8 multi-unit sequence.
  194. inline bool IsLeadByte(utf8char_t ch)
  195. {
  196. return ch >= 0xC0;
  197. }
  198. // Return true if ch is a byte that starts a well-formed UTF8 sequence (i.e. is an ASCII character or a valid UTF8 lead byte)
  199. inline bool IsStartByte(utf8char_t ch)
  200. {
  201. return ch < 0x80 || ch >= 0xC0;
  202. }
  203. // Returns true if ch is a UTF8 multi-unit sequence trail byte.
  204. inline bool IsTrailByte(utf8char_t ch)
  205. {
  206. return (ch & 0xC0) == 0x80;
  207. }
  208. // Returns true if ptr points to a well-formed UTF8
  209. inline bool IsCharStart(LPCUTF8 ptr)
  210. {
  211. return IsStartByte(*ptr);
  212. }
  213. // Return the start of the next well-formed UTF-8 sequence. Use NextChar() instead of
  214. // NextCharFull() since NextChar() avoid a call if ptr references a single byte sequence.
  215. LPCUTF8 NextCharFull(LPCUTF8 ptr);
  216. // Return the start of the next well-formed UTF-8 sequence.
  217. inline LPCUTF8 NextChar(LPCUTF8 ptr)
  218. {
  219. if (*ptr < 0x80) return ptr + 1;
  220. return NextCharFull(ptr);
  221. }
  222. // Return the start of the previous well-formed UTF-8 sequence prior to start or start if
  223. // if ptr is already start or no well-formed sequence starts a start. Use PrevChar() instead of
  224. // PrevCharFull() since PrevChar() avoids a call if the previous sequence is a single byte
  225. // sequence.
  226. LPCUTF8 PrevCharFull(LPCUTF8 ptr, LPCUTF8 start);
  227. // Return the start of the previous well-formed UTF-8 sequence prior to start or start if
  228. // if ptr is already start or no well-formed sequence starts a start.
  229. inline LPCUTF8 PrevChar(LPCUTF8 ptr, LPCUTF8 start)
  230. {
  231. if (ptr > start && *(ptr - 1) < 0x80) return ptr - 1;
  232. return PrevCharFull(ptr, start);
  233. }
  234. // Decode cb bytes from ptr to into buffer returning the number of characters converted and written to buffer
  235. _Ret_range_(0, pbEnd - _Old_(pbUtf8))
  236. size_t DecodeUnitsInto(_Out_writes_(pbEnd - pbUtf8) char16 *buffer, LPCUTF8& pbUtf8, LPCUTF8 pbEnd, DecodeOptions options = doDefault);
  237. // Decode cb bytes from ptr to into buffer returning the number of characters converted and written to buffer (excluding the null terminator)
  238. size_t DecodeUnitsIntoAndNullTerminate(__out_ecount(pbEnd - pbUtf8 + 1) __nullterminated char16 *buffer, LPCUTF8& pbUtf8, LPCUTF8 pbEnd, DecodeOptions options = doDefault);
  239. size_t DecodeUnitsIntoAndNullTerminateNoAdvance(__out_ecount(pbEnd - pbUtf8 + 1) __nullterminated char16 *buffer, LPCUTF8 pbUtf8, LPCUTF8 pbEnd, DecodeOptions options = doDefault);
  240. // Encode a UTF-8 sequence into a UTF-8 sequence (which is just a memcpy). This is included for convenience in templates
  241. // when the character encoding is a template parameter.
  242. __range(cch, cch)
  243. inline size_t EncodeInto(__out_ecount(cch) utf8char_t *buffer, const utf8char_t *source, size_t cch)
  244. {
  245. memcpy_s(buffer, cch * sizeof(utf8char_t), source, cch * sizeof(utf8char_t));
  246. return cch;
  247. }
  248. // Encode a UTF16-LE sequence of cch words into a UTF-8 sequence returning the number of bytes needed.
  249. // Since a UTF16 encoding can take up to 3 bytes buffer must refer to a buffer at least 3 times larger
  250. // than cch.
  251. // Returns the number of bytes copied into the buffer.
  252. __range(0, cch * 3)
  253. size_t EncodeInto(__out_ecount(cch * 3) LPUTF8 buffer, __in_ecount(cch) const char16 *source, charcount_t cch);
  254. // Like EncodeInto but ensures that buffer[return value] == 0.
  255. __range(0, cch * 3)
  256. size_t EncodeIntoAndNullTerminate(__out_ecount(cch * 3 + 1) utf8char_t *buffer, __in_ecount(cch) const char16 *source, charcount_t cch);
  257. // Like EncodeInto but ensures that buffer[return value] == 0.
  258. __range(0, cch * 3)
  259. size_t EncodeTrueUtf8IntoAndNullTerminate(__out_ecount(cch * 3 + 1) utf8char_t *buffer, __in_ecount(cch) const char16 *source, charcount_t cch);
  260. // Returns true if the pch refers to a UTF-16LE encoding of the given UTF-8 encoding bch.
  261. bool CharsAreEqual(__in_ecount(cch) LPCOLESTR pch, LPCUTF8 bch, LPCUTF8 end, size_t cch, DecodeOptions options = doDefault);
  262. // Convert the character index into a byte index.
  263. size_t CharacterIndexToByteIndex(__in_ecount(cbLength) LPCUTF8 pch, size_t cbLength, const charcount_t cchIndex, size_t cbStartIndex, charcount_t cchStartIndex, DecodeOptions options = doDefault);
  264. size_t CharacterIndexToByteIndex(__in_ecount(cbLength) LPCUTF8 pch, size_t cbLength, const charcount_t cchIndex, DecodeOptions options = doDefault);
  265. // Convert byte index into character index
  266. charcount_t ByteIndexIntoCharacterIndex(__in_ecount(cbIndex) LPCUTF8 pch, size_t cbIndex, DecodeOptions options = doDefault);
  267. }