ucs2_string.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/ucs2_string.h>
  3. #include <linux/module.h>
  4. /* Return the number of unicode characters in data */
  5. unsigned long
  6. ucs2_strnlen(const ucs2_char_t *s, size_t maxlength)
  7. {
  8. unsigned long length = 0;
  9. while (*s++ != 0 && length < maxlength)
  10. length++;
  11. return length;
  12. }
  13. EXPORT_SYMBOL(ucs2_strnlen);
  14. unsigned long
  15. ucs2_strlen(const ucs2_char_t *s)
  16. {
  17. return ucs2_strnlen(s, ~0UL);
  18. }
  19. EXPORT_SYMBOL(ucs2_strlen);
  20. /*
  21. * Return the number of bytes is the length of this string
  22. * Note: this is NOT the same as the number of unicode characters
  23. */
  24. unsigned long
  25. ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength)
  26. {
  27. return ucs2_strnlen(data, maxlength/sizeof(ucs2_char_t)) * sizeof(ucs2_char_t);
  28. }
  29. EXPORT_SYMBOL(ucs2_strsize);
  30. /**
  31. * ucs2_strscpy() - Copy a UCS2 string into a sized buffer.
  32. *
  33. * @dst: Pointer to the destination buffer where to copy the string to.
  34. * @src: Pointer to the source buffer where to copy the string from.
  35. * @count: Size of the destination buffer, in UCS2 (16-bit) characters.
  36. *
  37. * Like strscpy(), only for UCS2 strings.
  38. *
  39. * Copy the source string @src, or as much of it as fits, into the destination
  40. * buffer @dst. The behavior is undefined if the string buffers overlap. The
  41. * destination buffer @dst is always NUL-terminated, unless it's zero-sized.
  42. *
  43. * Return: The number of characters copied into @dst (excluding the trailing
  44. * %NUL terminator) or -E2BIG if @count is 0 or @src was truncated due to the
  45. * destination buffer being too small.
  46. */
  47. ssize_t ucs2_strscpy(ucs2_char_t *dst, const ucs2_char_t *src, size_t count)
  48. {
  49. long res;
  50. /*
  51. * Ensure that we have a valid amount of space. We need to store at
  52. * least one NUL-character.
  53. */
  54. if (count == 0 || WARN_ON_ONCE(count > INT_MAX / sizeof(*dst)))
  55. return -E2BIG;
  56. /*
  57. * Copy at most 'count' characters, return early if we find a
  58. * NUL-terminator.
  59. */
  60. for (res = 0; res < count; res++) {
  61. ucs2_char_t c;
  62. c = src[res];
  63. dst[res] = c;
  64. if (!c)
  65. return res;
  66. }
  67. /*
  68. * The loop above terminated without finding a NUL-terminator,
  69. * exceeding the 'count': Enforce proper NUL-termination and return
  70. * error.
  71. */
  72. dst[count - 1] = 0;
  73. return -E2BIG;
  74. }
  75. EXPORT_SYMBOL(ucs2_strscpy);
  76. int
  77. ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len)
  78. {
  79. while (1) {
  80. if (len == 0)
  81. return 0;
  82. if (*a < *b)
  83. return -1;
  84. if (*a > *b)
  85. return 1;
  86. if (*a == 0) /* implies *b == 0 */
  87. return 0;
  88. a++;
  89. b++;
  90. len--;
  91. }
  92. }
  93. EXPORT_SYMBOL(ucs2_strncmp);
  94. unsigned long
  95. ucs2_utf8size(const ucs2_char_t *src)
  96. {
  97. unsigned long i;
  98. unsigned long j = 0;
  99. for (i = 0; src[i]; i++) {
  100. u16 c = src[i];
  101. if (c >= 0x800)
  102. j += 3;
  103. else if (c >= 0x80)
  104. j += 2;
  105. else
  106. j += 1;
  107. }
  108. return j;
  109. }
  110. EXPORT_SYMBOL(ucs2_utf8size);
  111. /*
  112. * copy at most maxlength bytes of whole utf8 characters to dest from the
  113. * ucs2 string src.
  114. *
  115. * The return value is the number of characters copied, not including the
  116. * final NUL character.
  117. */
  118. unsigned long
  119. ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength)
  120. {
  121. unsigned int i;
  122. unsigned long j = 0;
  123. unsigned long limit = ucs2_strnlen(src, maxlength);
  124. for (i = 0; maxlength && i < limit; i++) {
  125. u16 c = src[i];
  126. if (c >= 0x800) {
  127. if (maxlength < 3)
  128. break;
  129. maxlength -= 3;
  130. dest[j++] = 0xe0 | (c & 0xf000) >> 12;
  131. dest[j++] = 0x80 | (c & 0x0fc0) >> 6;
  132. dest[j++] = 0x80 | (c & 0x003f);
  133. } else if (c >= 0x80) {
  134. if (maxlength < 2)
  135. break;
  136. maxlength -= 2;
  137. dest[j++] = 0xc0 | (c & 0x7c0) >> 6;
  138. dest[j++] = 0x80 | (c & 0x03f);
  139. } else {
  140. maxlength -= 1;
  141. dest[j++] = c & 0x7f;
  142. }
  143. }
  144. if (maxlength)
  145. dest[j] = '\0';
  146. return j;
  147. }
  148. EXPORT_SYMBOL(ucs2_as_utf8);
  149. MODULE_DESCRIPTION("UCS2 string handling");
  150. MODULE_LICENSE("GPL v2");