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