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