charset.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * charset conversion utils
  4. *
  5. * Copyright (c) 2017 Rob Clark
  6. */
  7. #include <charset.h>
  8. #include <malloc.h>
  9. /*
  10. * utf8/utf16 conversion mostly lifted from grub
  11. */
  12. size_t utf16_strlen(const uint16_t *in)
  13. {
  14. size_t i;
  15. for (i = 0; in[i]; i++);
  16. return i;
  17. }
  18. size_t utf16_strnlen(const uint16_t *in, size_t count)
  19. {
  20. size_t i;
  21. for (i = 0; count-- && in[i]; i++);
  22. return i;
  23. }
  24. uint16_t *utf16_strcpy(uint16_t *dest, const uint16_t *src)
  25. {
  26. uint16_t *tmp = dest;
  27. while ((*dest++ = *src++) != '\0')
  28. /* nothing */;
  29. return tmp;
  30. }
  31. uint16_t *utf16_strdup(const uint16_t *s)
  32. {
  33. uint16_t *new;
  34. if (!s || !(new = malloc((utf16_strlen(s) + 1) * 2)))
  35. return NULL;
  36. utf16_strcpy(new, s);
  37. return new;
  38. }
  39. /* Convert UTF-16 to UTF-8. */
  40. uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
  41. {
  42. uint32_t code_high = 0;
  43. while (size--) {
  44. uint32_t code = *src++;
  45. if (code_high) {
  46. if (code >= 0xDC00 && code <= 0xDFFF) {
  47. /* Surrogate pair. */
  48. code = ((code_high - 0xD800) << 10) + (code - 0xDC00) + 0x10000;
  49. *dest++ = (code >> 18) | 0xF0;
  50. *dest++ = ((code >> 12) & 0x3F) | 0x80;
  51. *dest++ = ((code >> 6) & 0x3F) | 0x80;
  52. *dest++ = (code & 0x3F) | 0x80;
  53. } else {
  54. /* Error... */
  55. *dest++ = '?';
  56. /* *src may be valid. Don't eat it. */
  57. src--;
  58. }
  59. code_high = 0;
  60. } else {
  61. if (code <= 0x007F) {
  62. *dest++ = code;
  63. } else if (code <= 0x07FF) {
  64. *dest++ = (code >> 6) | 0xC0;
  65. *dest++ = (code & 0x3F) | 0x80;
  66. } else if (code >= 0xD800 && code <= 0xDBFF) {
  67. code_high = code;
  68. continue;
  69. } else if (code >= 0xDC00 && code <= 0xDFFF) {
  70. /* Error... */
  71. *dest++ = '?';
  72. } else if (code < 0x10000) {
  73. *dest++ = (code >> 12) | 0xE0;
  74. *dest++ = ((code >> 6) & 0x3F) | 0x80;
  75. *dest++ = (code & 0x3F) | 0x80;
  76. } else {
  77. *dest++ = (code >> 18) | 0xF0;
  78. *dest++ = ((code >> 12) & 0x3F) | 0x80;
  79. *dest++ = ((code >> 6) & 0x3F) | 0x80;
  80. *dest++ = (code & 0x3F) | 0x80;
  81. }
  82. }
  83. }
  84. return dest;
  85. }
  86. uint16_t *utf8_to_utf16(uint16_t *dest, const uint8_t *src, size_t size)
  87. {
  88. while (size--) {
  89. int extension_bytes;
  90. uint32_t code;
  91. extension_bytes = 0;
  92. if (*src <= 0x7f) {
  93. code = *src++;
  94. /* Exit on zero byte */
  95. if (!code)
  96. size = 0;
  97. } else if (*src <= 0xbf) {
  98. /* Illegal code */
  99. code = '?';
  100. } else if (*src <= 0xdf) {
  101. code = *src++ & 0x1f;
  102. extension_bytes = 1;
  103. } else if (*src <= 0xef) {
  104. code = *src++ & 0x0f;
  105. extension_bytes = 2;
  106. } else if (*src <= 0xf7) {
  107. code = *src++ & 0x07;
  108. extension_bytes = 3;
  109. } else {
  110. /* Illegal code */
  111. code = '?';
  112. }
  113. for (; extension_bytes && size; --size, --extension_bytes) {
  114. if ((*src & 0xc0) == 0x80) {
  115. code <<= 6;
  116. code |= *src++ & 0x3f;
  117. } else {
  118. /* Illegal code */
  119. code = '?';
  120. ++src;
  121. --size;
  122. break;
  123. }
  124. }
  125. if (code < 0x10000) {
  126. *dest++ = code;
  127. } else {
  128. /*
  129. * Simplified expression for
  130. * (((code - 0x10000) >> 10) & 0x3ff) | 0xd800
  131. */
  132. *dest++ = (code >> 10) + 0xd7c0;
  133. *dest++ = (code & 0x3ff) | 0xdc00;
  134. }
  135. }
  136. return dest;
  137. }