wchar.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // This file is https://github.com/orofarne/gowchar/blob/master/gowchar.go
  2. //
  3. // It was vendored inline to work around CGO limitations that don't allow C types
  4. // to directly cross package API boundaries.
  5. //
  6. // The vendored file is licensed under the 3-clause BSD license, according to:
  7. // https://github.com/orofarne/gowchar/blob/master/LICENSE
  8. // +build !ios
  9. // +build linux darwin windows
  10. package hid
  11. /*
  12. #include <wchar.h>
  13. const size_t SIZEOF_WCHAR_T = sizeof(wchar_t);
  14. void gowchar_set (wchar_t *arr, int pos, wchar_t val)
  15. {
  16. arr[pos] = val;
  17. }
  18. wchar_t gowchar_get (wchar_t *arr, int pos)
  19. {
  20. return arr[pos];
  21. }
  22. */
  23. import "C"
  24. import (
  25. "fmt"
  26. "unicode/utf16"
  27. "unicode/utf8"
  28. )
  29. var sizeofWcharT C.size_t = C.size_t(C.SIZEOF_WCHAR_T)
  30. func stringToWcharT(s string) (*C.wchar_t, C.size_t) {
  31. switch sizeofWcharT {
  32. case 2:
  33. return stringToWchar2(s) // Windows
  34. case 4:
  35. return stringToWchar4(s) // Unix
  36. default:
  37. panic(fmt.Sprintf("Invalid sizeof(wchar_t) = %v", sizeofWcharT))
  38. }
  39. }
  40. func wcharTToString(s *C.wchar_t) (string, error) {
  41. switch sizeofWcharT {
  42. case 2:
  43. return wchar2ToString(s) // Windows
  44. case 4:
  45. return wchar4ToString(s) // Unix
  46. default:
  47. panic(fmt.Sprintf("Invalid sizeof(wchar_t) = %v", sizeofWcharT))
  48. }
  49. }
  50. func wcharTNToString(s *C.wchar_t, size C.size_t) (string, error) {
  51. switch sizeofWcharT {
  52. case 2:
  53. return wchar2NToString(s, size) // Windows
  54. case 4:
  55. return wchar4NToString(s, size) // Unix
  56. default:
  57. panic(fmt.Sprintf("Invalid sizeof(wchar_t) = %v", sizeofWcharT))
  58. }
  59. }
  60. // Windows
  61. func stringToWchar2(s string) (*C.wchar_t, C.size_t) {
  62. var slen int
  63. s1 := s
  64. for len(s1) > 0 {
  65. r, size := utf8.DecodeRuneInString(s1)
  66. if er, _ := utf16.EncodeRune(r); er == '\uFFFD' {
  67. slen += 1
  68. } else {
  69. slen += 2
  70. }
  71. s1 = s1[size:]
  72. }
  73. slen++ // \0
  74. res := C.malloc(C.size_t(slen) * sizeofWcharT)
  75. var i int
  76. for len(s) > 0 {
  77. r, size := utf8.DecodeRuneInString(s)
  78. if r1, r2 := utf16.EncodeRune(r); r1 != '\uFFFD' {
  79. C.gowchar_set((*C.wchar_t)(res), C.int(i), C.wchar_t(r1))
  80. i++
  81. C.gowchar_set((*C.wchar_t)(res), C.int(i), C.wchar_t(r2))
  82. i++
  83. } else {
  84. C.gowchar_set((*C.wchar_t)(res), C.int(i), C.wchar_t(r))
  85. i++
  86. }
  87. s = s[size:]
  88. }
  89. C.gowchar_set((*C.wchar_t)(res), C.int(slen-1), C.wchar_t(0)) // \0
  90. return (*C.wchar_t)(res), C.size_t(slen)
  91. }
  92. // Unix
  93. func stringToWchar4(s string) (*C.wchar_t, C.size_t) {
  94. slen := utf8.RuneCountInString(s)
  95. slen++ // \0
  96. res := C.malloc(C.size_t(slen) * sizeofWcharT)
  97. var i int
  98. for len(s) > 0 {
  99. r, size := utf8.DecodeRuneInString(s)
  100. C.gowchar_set((*C.wchar_t)(res), C.int(i), C.wchar_t(r))
  101. s = s[size:]
  102. i++
  103. }
  104. C.gowchar_set((*C.wchar_t)(res), C.int(slen-1), C.wchar_t(0)) // \0
  105. return (*C.wchar_t)(res), C.size_t(slen)
  106. }
  107. // Windows
  108. func wchar2ToString(s *C.wchar_t) (string, error) {
  109. var i int
  110. var res string
  111. for {
  112. ch := C.gowchar_get(s, C.int(i))
  113. if ch == 0 {
  114. break
  115. }
  116. r := rune(ch)
  117. i++
  118. if !utf16.IsSurrogate(r) {
  119. if !utf8.ValidRune(r) {
  120. err := fmt.Errorf("Invalid rune at position %v", i)
  121. return "", err
  122. }
  123. res += string(r)
  124. } else {
  125. ch2 := C.gowchar_get(s, C.int(i))
  126. r2 := rune(ch2)
  127. r12 := utf16.DecodeRune(r, r2)
  128. if r12 == '\uFFFD' {
  129. err := fmt.Errorf("Invalid surrogate pair at position %v", i-1)
  130. return "", err
  131. }
  132. res += string(r12)
  133. i++
  134. }
  135. }
  136. return res, nil
  137. }
  138. // Unix
  139. func wchar4ToString(s *C.wchar_t) (string, error) {
  140. var i int
  141. var res string
  142. for {
  143. ch := C.gowchar_get(s, C.int(i))
  144. if ch == 0 {
  145. break
  146. }
  147. r := rune(ch)
  148. if !utf8.ValidRune(r) {
  149. err := fmt.Errorf("Invalid rune at position %v", i)
  150. return "", err
  151. }
  152. res += string(r)
  153. i++
  154. }
  155. return res, nil
  156. }
  157. // Windows
  158. func wchar2NToString(s *C.wchar_t, size C.size_t) (string, error) {
  159. var i int
  160. var res string
  161. N := int(size)
  162. for i < N {
  163. ch := C.gowchar_get(s, C.int(i))
  164. if ch == 0 {
  165. break
  166. }
  167. r := rune(ch)
  168. i++
  169. if !utf16.IsSurrogate(r) {
  170. if !utf8.ValidRune(r) {
  171. err := fmt.Errorf("Invalid rune at position %v", i)
  172. return "", err
  173. }
  174. res += string(r)
  175. } else {
  176. if i >= N {
  177. err := fmt.Errorf("Invalid surrogate pair at position %v", i-1)
  178. return "", err
  179. }
  180. ch2 := C.gowchar_get(s, C.int(i))
  181. r2 := rune(ch2)
  182. r12 := utf16.DecodeRune(r, r2)
  183. if r12 == '\uFFFD' {
  184. err := fmt.Errorf("Invalid surrogate pair at position %v", i-1)
  185. return "", err
  186. }
  187. res += string(r12)
  188. i++
  189. }
  190. }
  191. return res, nil
  192. }
  193. // Unix
  194. func wchar4NToString(s *C.wchar_t, size C.size_t) (string, error) {
  195. var i int
  196. var res string
  197. N := int(size)
  198. for i < N {
  199. ch := C.gowchar_get(s, C.int(i))
  200. r := rune(ch)
  201. if !utf8.ValidRune(r) {
  202. err := fmt.Errorf("Invalid rune at position %v", i)
  203. return "", err
  204. }
  205. res += string(r)
  206. i++
  207. }
  208. return res, nil
  209. }