aboutsummaryrefslogtreecommitdiff
path: root/src/utf8.c
blob: cebd8726800f6be2c2bb4f74699ff39cd6af6b12 (plain)
  1. #include <stdlib.h>
  2. #include <stdint.h>
  3. #include <unistd.h>
  4. #include <assert.h>
  5. #include "stmd.h"
  6. static const int8_t utf8proc_utf8class[256] = {
  7. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  8. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  9. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  10. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  11. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  12. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  13. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  14. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  15. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  16. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  17. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  18. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  19. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  20. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  21. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  22. 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0 };
  23. ssize_t utf8proc_charlen(const uint8_t *str, ssize_t str_len)
  24. {
  25. ssize_t length, i;
  26. if (!str_len)
  27. return 0;
  28. length = utf8proc_utf8class[str[0]];
  29. if (!length)
  30. return -1;
  31. if (str_len >= 0 && length > str_len)
  32. return -1;
  33. for (i = 1; i < length; i++) {
  34. if ((str[i] & 0xC0) != 0x80)
  35. return -1;
  36. }
  37. return length;
  38. }
  39. ssize_t utf8proc_iterate(const uint8_t *str, ssize_t str_len, int32_t *dst)
  40. {
  41. ssize_t length;
  42. int32_t uc = -1;
  43. *dst = -1;
  44. length = utf8proc_charlen(str, str_len);
  45. if (length < 0)
  46. return -1;
  47. switch (length) {
  48. case 1:
  49. uc = str[0];
  50. break;
  51. case 2:
  52. uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F);
  53. if (uc < 0x80) uc = -1;
  54. break;
  55. case 3:
  56. uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6)
  57. + (str[2] & 0x3F);
  58. if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000) ||
  59. (uc >= 0xFDD0 && uc < 0xFDF0)) uc = -1;
  60. break;
  61. case 4:
  62. uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12)
  63. + ((str[2] & 0x3F) << 6) + (str[3] & 0x3F);
  64. if (uc < 0x10000 || uc >= 0x110000) uc = -1;
  65. break;
  66. }
  67. if (uc < 0 || ((uc & 0xFFFF) >= 0xFFFE))
  68. return -1;
  69. *dst = uc;
  70. return length;
  71. }
  72. void utf8proc_encode_char(int32_t uc, strbuf *buf)
  73. {
  74. unsigned char dst[4];
  75. int len = 0;
  76. if (uc < 0x00) {
  77. assert(false);
  78. } else if (uc < 0x80) {
  79. dst[0] = uc;
  80. len = 1;
  81. } else if (uc < 0x800) {
  82. dst[0] = 0xC0 + (uc >> 6);
  83. dst[1] = 0x80 + (uc & 0x3F);
  84. len = 2;
  85. } else if (uc == 0xFFFF) {
  86. dst[0] = 0xFF;
  87. len = 1;
  88. } else if (uc == 0xFFFE) {
  89. dst[0] = 0xFE;
  90. len = 1;
  91. } else if (uc < 0x10000) {
  92. dst[0] = 0xE0 + (uc >> 12);
  93. dst[1] = 0x80 + ((uc >> 6) & 0x3F);
  94. dst[2] = 0x80 + (uc & 0x3F);
  95. len = 3;
  96. } else if (uc < 0x110000) {
  97. dst[0] = 0xF0 + (uc >> 18);
  98. dst[1] = 0x80 + ((uc >> 12) & 0x3F);
  99. dst[2] = 0x80 + ((uc >> 6) & 0x3F);
  100. dst[3] = 0x80 + (uc & 0x3F);
  101. len = 4;
  102. } else {
  103. assert(false);
  104. }
  105. strbuf_put(buf, dst, len);
  106. }
  107. void utf8proc_case_fold(strbuf *dest, const unsigned char *str, int len)
  108. {
  109. int32_t c;
  110. #define bufpush(x) \
  111. utf8proc_encode_char(x, dest)
  112. while (len > 0) {
  113. ssize_t char_len = utf8proc_iterate(str, len, &c);
  114. if (char_len < 0) {
  115. bufpush(0xFFFD);
  116. continue;
  117. }
  118. #include "case_fold_switch.inc"
  119. str += char_len;
  120. len -= char_len;
  121. }
  122. }