fs_string_util.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include "common/assert.h"
  5. namespace FileSys {
  6. template <typename T>
  7. constexpr int Strlen(const T* str) {
  8. ASSERT(str != nullptr);
  9. int length = 0;
  10. while (*str++) {
  11. ++length;
  12. }
  13. return length;
  14. }
  15. template <typename T>
  16. constexpr int Strnlen(const T* str, std::size_t count) {
  17. return Strnlen(str, static_cast<int>(count));
  18. }
  19. template <typename T>
  20. constexpr int Strnlen(const T* str, int count) {
  21. ASSERT(str != nullptr);
  22. ASSERT(count >= 0);
  23. int length = 0;
  24. while (count-- && *str++) {
  25. ++length;
  26. }
  27. return length;
  28. }
  29. template <typename T>
  30. constexpr int Strncmp(const T* lhs, const T* rhs, std::size_t count) {
  31. return Strncmp(lhs, rhs, static_cast<int>(count));
  32. }
  33. template <typename T>
  34. constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
  35. ASSERT(lhs != nullptr);
  36. ASSERT(rhs != nullptr);
  37. ASSERT(count >= 0);
  38. if (count == 0) {
  39. return 0;
  40. }
  41. T l, r;
  42. do {
  43. l = *(lhs++);
  44. r = *(rhs++);
  45. } while (l && (l == r) && (--count));
  46. return l - r;
  47. }
  48. template <typename T>
  49. static constexpr int Strlcpy(T* dst, const T* src, std::size_t count) {
  50. return Strlcpy<T>(dst, src, static_cast<int>(count));
  51. }
  52. template <typename T>
  53. static constexpr int Strlcpy(T* dst, const T* src, int count) {
  54. ASSERT(dst != nullptr);
  55. ASSERT(src != nullptr);
  56. const T* cur = src;
  57. if (count > 0) {
  58. while ((--count) && *cur) {
  59. *(dst++) = *(cur++);
  60. }
  61. *dst = 0;
  62. }
  63. while (*cur) {
  64. cur++;
  65. }
  66. return static_cast<int>(cur - src);
  67. }
  68. enum CharacterEncodingResult {
  69. CharacterEncodingResult_Success = 0,
  70. CharacterEncodingResult_InsufficientLength = 1,
  71. CharacterEncodingResult_InvalidFormat = 2,
  72. };
  73. namespace impl {
  74. class CharacterEncodingHelper {
  75. public:
  76. static constexpr int8_t Utf8NBytesInnerTable[0x100 + 1] = {
  77. -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  78. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  79. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  80. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  81. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  82. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  83. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  84. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
  85. 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8,
  86. };
  87. static constexpr char GetUtf8NBytes(size_t i) {
  88. return static_cast<char>(Utf8NBytesInnerTable[1 + i]);
  89. }
  90. };
  91. } // namespace impl
  92. constexpr inline CharacterEncodingResult ConvertCharacterUtf8ToUtf32(u32* dst, const char* src) {
  93. // Check pre-conditions
  94. ASSERT(dst != nullptr);
  95. ASSERT(src != nullptr);
  96. // Perform the conversion
  97. const auto* p = src;
  98. switch (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[0]))) {
  99. case 1:
  100. *dst = static_cast<u32>(p[0]);
  101. return CharacterEncodingResult_Success;
  102. case 2:
  103. if ((static_cast<u32>(p[0]) & 0x1E) != 0) {
  104. if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) ==
  105. 0) {
  106. *dst = (static_cast<u32>(p[0] & 0x1F) << 6) | (static_cast<u32>(p[1] & 0x3F) << 0);
  107. return CharacterEncodingResult_Success;
  108. }
  109. }
  110. break;
  111. case 3:
  112. if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == 0 &&
  113. impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[2])) == 0) {
  114. const u32 c = (static_cast<u32>(p[0] & 0xF) << 12) |
  115. (static_cast<u32>(p[1] & 0x3F) << 6) |
  116. (static_cast<u32>(p[2] & 0x3F) << 0);
  117. if ((c & 0xF800) != 0 && (c & 0xF800) != 0xD800) {
  118. *dst = c;
  119. return CharacterEncodingResult_Success;
  120. }
  121. }
  122. return CharacterEncodingResult_InvalidFormat;
  123. case 4:
  124. if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == 0 &&
  125. impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[2])) == 0 &&
  126. impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[3])) == 0) {
  127. const u32 c =
  128. (static_cast<u32>(p[0] & 0x7) << 18) | (static_cast<u32>(p[1] & 0x3F) << 12) |
  129. (static_cast<u32>(p[2] & 0x3F) << 6) | (static_cast<u32>(p[3] & 0x3F) << 0);
  130. if (c >= 0x10000 && c < 0x110000) {
  131. *dst = c;
  132. return CharacterEncodingResult_Success;
  133. }
  134. }
  135. return CharacterEncodingResult_InvalidFormat;
  136. default:
  137. break;
  138. }
  139. // We failed to convert
  140. return CharacterEncodingResult_InvalidFormat;
  141. }
  142. constexpr inline CharacterEncodingResult PickOutCharacterFromUtf8String(char* dst,
  143. const char** str) {
  144. // Check pre-conditions
  145. ASSERT(dst != nullptr);
  146. ASSERT(str != nullptr);
  147. ASSERT(*str != nullptr);
  148. // Clear the output
  149. dst[0] = 0;
  150. dst[1] = 0;
  151. dst[2] = 0;
  152. dst[3] = 0;
  153. // Perform the conversion
  154. const auto* p = *str;
  155. u32 c = static_cast<u32>(*p);
  156. switch (impl::CharacterEncodingHelper::GetUtf8NBytes(c)) {
  157. case 1:
  158. dst[0] = (*str)[0];
  159. ++(*str);
  160. break;
  161. case 2:
  162. if ((p[0] & 0x1E) != 0) {
  163. if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) ==
  164. 0) {
  165. c = (static_cast<u32>(p[0] & 0x1F) << 6) | (static_cast<u32>(p[1] & 0x3F) << 0);
  166. dst[0] = (*str)[0];
  167. dst[1] = (*str)[1];
  168. (*str) += 2;
  169. break;
  170. }
  171. }
  172. return CharacterEncodingResult_InvalidFormat;
  173. case 3:
  174. if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == 0 &&
  175. impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[2])) == 0) {
  176. c = (static_cast<u32>(p[0] & 0xF) << 12) | (static_cast<u32>(p[1] & 0x3F) << 6) |
  177. (static_cast<u32>(p[2] & 0x3F) << 0);
  178. if ((c & 0xF800) != 0 && (c & 0xF800) != 0xD800) {
  179. dst[0] = (*str)[0];
  180. dst[1] = (*str)[1];
  181. dst[2] = (*str)[2];
  182. (*str) += 3;
  183. break;
  184. }
  185. }
  186. return CharacterEncodingResult_InvalidFormat;
  187. case 4:
  188. if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[1])) == 0 &&
  189. impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[2])) == 0 &&
  190. impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast<unsigned char>(p[3])) == 0) {
  191. c = (static_cast<u32>(p[0] & 0x7) << 18) | (static_cast<u32>(p[1] & 0x3F) << 12) |
  192. (static_cast<u32>(p[2] & 0x3F) << 6) | (static_cast<u32>(p[3] & 0x3F) << 0);
  193. if (c >= 0x10000 && c < 0x110000) {
  194. dst[0] = (*str)[0];
  195. dst[1] = (*str)[1];
  196. dst[2] = (*str)[2];
  197. dst[3] = (*str)[3];
  198. (*str) += 4;
  199. break;
  200. }
  201. }
  202. return CharacterEncodingResult_InvalidFormat;
  203. default:
  204. return CharacterEncodingResult_InvalidFormat;
  205. }
  206. return CharacterEncodingResult_Success;
  207. }
  208. } // namespace FileSys