aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/GeertJohan/cgo.wchar
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/GeertJohan/cgo.wchar')
-rw-r--r--vendor/github.com/GeertJohan/cgo.wchar/convert.go274
-rw-r--r--vendor/github.com/GeertJohan/cgo.wchar/readme.md24
-rw-r--r--vendor/github.com/GeertJohan/cgo.wchar/wchar.go159
-rw-r--r--vendor/github.com/GeertJohan/cgo.wchar/wchar_notwin.go6
-rw-r--r--vendor/github.com/GeertJohan/cgo.wchar/wchar_test.go105
-rw-r--r--vendor/github.com/GeertJohan/cgo.wchar/wchar_windows.go4
6 files changed, 572 insertions, 0 deletions
diff --git a/vendor/github.com/GeertJohan/cgo.wchar/convert.go b/vendor/github.com/GeertJohan/cgo.wchar/convert.go
new file mode 100644
index 0000000..70f1b1b
--- /dev/null
+++ b/vendor/github.com/GeertJohan/cgo.wchar/convert.go
@@ -0,0 +1,274 @@
+package wchar
+
+/*
+#cgo darwin LDFLAGS: -liconv
+#cgo windows LDFLAGS: -liconv
+#include <stdlib.h>
+#ifdef __APPLE__
+# define LIBICONV_PLUG 1
+#endif
+#include <iconv.h>
+#include <wchar.h>
+*/
+import "C"
+
+import (
+ "encoding/binary"
+ "fmt"
+ "unsafe"
+)
+
+// iconv charset strings
+var (
+ iconvCharsetWchar = C.CString("wchar_t//TRANSLIT")
+ iconvCharsetChar = C.CString("//TRANSLIT")
+ iconvCharsetAscii = C.CString("ascii//TRANSLIT")
+ iconvCharsetUtf8 = C.CString("utf-8//TRANSLIT")
+)
+
+// iconv documentation:
+// Use iconv. It seems to support conversion between char and wchar_t
+// http://www.gnu.org/savannah-checkouts/gnu/libiconv/documentation/libiconv-1.13/iconv_open.3.html
+// http://www.gnu.org/savannah-checkouts/gnu/libiconv/documentation/libiconv-1.13/iconv.3.html
+// http://www.gnu.org/savannah-checkouts/gnu/libiconv/documentation/libiconv-1.13/iconv_close.3.html
+
+// Internal helper function, wrapped by several other functions
+func convertGoStringToWcharString(input string) (output WcharString, err error) {
+ // quick return when input is an empty string
+ if input == "" {
+ return NewWcharString(0), nil
+ }
+
+ // open iconv
+ iconv, errno := C.iconv_open(iconvCharsetWchar, iconvCharsetUtf8)
+ if iconv == nil || errno != nil {
+ return nil, fmt.Errorf("Could not open iconv instance: %s", errno)
+ }
+ defer C.iconv_close(iconv)
+
+ // calculate bufferSizes in bytes for C
+ bytesLeftInCSize := C.size_t(len([]byte(input))) // count exact amount of bytes from input
+ bytesLeftOutCSize := C.size_t(len(input) * 4) // wide char seems to be 4 bytes for every single- or multi-byte character. Not very sure though.
+
+ // input for C. makes a copy using C malloc and therefore should be free'd.
+ inputCString := C.CString(input)
+ defer C.free(unsafe.Pointer(inputCString))
+
+ // create output buffer
+ outputChars := make([]int8, len(input)*4)
+
+ // output for C
+ outputCString := (*C.char)(unsafe.Pointer(&outputChars[0]))
+
+ // call iconv for conversion of charsets, return on error
+ _, errno = C.iconv(iconv, &inputCString, &bytesLeftInCSize, &outputCString, &bytesLeftOutCSize)
+ if errno != nil {
+ return nil, errno
+ }
+
+ // convert []int8 to WcharString
+ // create WcharString with same length as input, and one extra position for the null terminator.
+ output = make(WcharString, 0, len(input)+1)
+ // create buff to convert each outputChar
+ wcharAsByteAry := make([]byte, 4)
+ // loop for as long as there are output chars
+ for len(outputChars) >= 4 {
+ // create 4 position byte slice
+ wcharAsByteAry[0] = byte(outputChars[0])
+ wcharAsByteAry[1] = byte(outputChars[1])
+ wcharAsByteAry[2] = byte(outputChars[2])
+ wcharAsByteAry[3] = byte(outputChars[3])
+ // combine 4 position byte slice into uint32
+ wcharAsUint32 := binary.LittleEndian.Uint32(wcharAsByteAry)
+ // find null terminator (doing this right?)
+ if wcharAsUint32 == 0x0 {
+ break
+ }
+ // append uint32 to outputUint32
+ output = append(output, Wchar(wcharAsUint32))
+ // reslice the outputChars
+ outputChars = outputChars[4:]
+ }
+ // Add null terminator
+ output = append(output, Wchar(0x0))
+
+ return output, nil
+}
+
+// Internal helper function, wrapped by several other functions
+func convertWcharStringToGoString(ws WcharString) (output string, err error) {
+ // return empty string if len(input) == 0
+ if len(ws) == 0 {
+ return "", nil
+ }
+
+ // open iconv
+ iconv, errno := C.iconv_open(iconvCharsetUtf8, iconvCharsetWchar)
+ if iconv == nil || errno != nil {
+ return "", fmt.Errorf("Could not open iconv instance: %s", errno.Error())
+ }
+ defer C.iconv_close(iconv)
+
+ inputAsCChars := make([]C.char, 0, len(ws)*4)
+ wcharAsBytes := make([]byte, 4)
+ for _, nextWchar := range ws {
+ // find null terminator
+ if nextWchar == 0 {
+ // Return empty string if there are no chars in buffer
+ //++ FIXME: this should NEVER be the case because input is checked at the begin of this function.
+ if len(inputAsCChars) == 0 {
+ return "", nil
+ }
+ break
+ }
+
+ // split Wchar into bytes
+ binary.LittleEndian.PutUint32(wcharAsBytes, uint32(nextWchar))
+
+ // append the bytes as C.char to inputAsCChars
+ for i := 0; i < 4; i++ {
+ inputAsCChars = append(inputAsCChars, C.char(wcharAsBytes[i]))
+ }
+ }
+
+ // input for C
+ inputAsCCharsPtr := &inputAsCChars[0]
+
+ // calculate buffer size for input
+ bytesLeftInCSize := C.size_t(len(inputAsCChars))
+
+ // calculate buffer size for output
+ bytesLeftOutCSize := C.size_t(len(inputAsCChars))
+
+ // create output buffer
+ outputChars := make([]C.char, bytesLeftOutCSize)
+
+ // output buffer pointer for C
+ outputCharsPtr := &outputChars[0]
+
+ // call iconv for conversion of charsets, return on error
+ _, errno = C.iconv(iconv, &inputAsCCharsPtr, &bytesLeftInCSize, &outputCharsPtr, &bytesLeftOutCSize)
+ if errno != nil {
+ return "", errno
+ }
+
+ // conver output buffer to go string
+ output = C.GoString((*C.char)(&outputChars[0]))
+
+ return output, nil
+}
+
+// Internal helper function, wrapped by other functions
+func convertGoRuneToWchar(r rune) (output Wchar, err error) {
+ // quick return when input is an empty string
+ if r == '\000' {
+ return Wchar(0), nil
+ }
+
+ // open iconv
+ iconv, errno := C.iconv_open(iconvCharsetWchar, iconvCharsetUtf8)
+ if iconv == nil || errno != nil {
+ return Wchar(0), fmt.Errorf("Could not open iconv instance: %s", errno)
+ }
+ defer C.iconv_close(iconv)
+
+ // bufferSizes for C
+ bytesLeftInCSize := C.size_t(4)
+ bytesLeftOutCSize := C.size_t(4 * 4)
+ // TODO/FIXME: the last 4 bytes as indicated by bytesLeftOutCSize wont be used...
+ // iconv assumes each given char to be one wchar.
+ // in this case we know that the given 4 chars will actually be one unicode-point and therefore will result in one wchar.
+ // hence, we give the iconv library a buffer of 4 char's size, and tell the library that it has a buffer of 32 char's size.
+ // if the rune would actually contain 2 unicode-point's this will result in massive failure (and probably the end of a process' life)
+
+ // input for C. makes a copy using C malloc and therefore should be free'd.
+ runeCString := C.CString(string(r))
+ defer C.free(unsafe.Pointer(runeCString))
+
+ // create output buffer
+ outputChars := make([]C.char, 4)
+
+ // output buffer pointer for C
+ outputCharsPtr := &outputChars[0]
+
+ // call iconv for conversion of charsets
+ _, errno = C.iconv(iconv, &runeCString, &bytesLeftInCSize, &outputCharsPtr, &bytesLeftOutCSize)
+ if errno != nil {
+ return '\000', errno
+ }
+
+ // convert C.char's to Wchar
+ wcharAsByteAry := make([]byte, 4)
+ wcharAsByteAry[0] = byte(outputChars[0])
+ wcharAsByteAry[1] = byte(outputChars[1])
+ wcharAsByteAry[2] = byte(outputChars[2])
+ wcharAsByteAry[3] = byte(outputChars[3])
+
+ // combine 4 position byte slice into uint32 and convert to Wchar.
+ wcharAsUint32 := binary.LittleEndian.Uint32(wcharAsByteAry)
+ output = Wchar(wcharAsUint32)
+
+ return output, nil
+}
+
+// Internal helper function, wrapped by several other functions
+func convertWcharToGoRune(w Wchar) (output rune, err error) {
+ // return if len(input) == 0
+ if w == 0 {
+ return '\000', nil
+ }
+
+ // open iconv
+ iconv, errno := C.iconv_open(iconvCharsetUtf8, iconvCharsetWchar)
+ if iconv == nil || errno != nil {
+ return '\000', fmt.Errorf("Could not open iconv instance: %s", errno.Error())
+ }
+ defer C.iconv_close(iconv)
+
+ // split Wchar into bytes
+ wcharAsBytes := make([]byte, 4)
+ binary.LittleEndian.PutUint32(wcharAsBytes, uint32(w))
+
+ // place the wcharAsBytes into wcharAsCChars
+ // TODO: use unsafe.Pointer here to do the conversion?
+ wcharAsCChars := make([]C.char, 0, 4)
+ for i := 0; i < 4; i++ {
+ wcharAsCChars = append(wcharAsCChars, C.char(wcharAsBytes[i]))
+ }
+
+ // pointer to the first wcharAsCChars
+ wcharAsCCharsPtr := &wcharAsCChars[0]
+
+ // calculate buffer size for input
+ bytesLeftInCSize := C.size_t(4)
+
+ // calculate buffer size for output
+ bytesLeftOutCSize := C.size_t(4)
+
+ // create output buffer
+ outputChars := make([]C.char, 4)
+
+ // output buffer pointer for C
+ outputCharsPtr := &outputChars[0]
+
+ // call iconv for conversion of charsets
+ _, errno = C.iconv(iconv, &wcharAsCCharsPtr, &bytesLeftInCSize, &outputCharsPtr, &bytesLeftOutCSize)
+ if errno != nil {
+ return '\000', errno
+ }
+
+ // convert outputChars ([]int8, len 4) to Wchar
+ // TODO: can this conversion be done easier by using this: ?
+ // output = *((*rune)(unsafe.Pointer(&outputChars[0])))
+ runeAsByteAry := make([]byte, 4)
+ runeAsByteAry[0] = byte(outputChars[0])
+ runeAsByteAry[1] = byte(outputChars[1])
+ runeAsByteAry[2] = byte(outputChars[2])
+ runeAsByteAry[3] = byte(outputChars[3])
+
+ // combine 4 position byte slice into uint32 and convert to rune.
+ runeAsUint32 := binary.LittleEndian.Uint32(runeAsByteAry)
+ output = rune(runeAsUint32)
+
+ return output, nil
+}
diff --git a/vendor/github.com/GeertJohan/cgo.wchar/readme.md b/vendor/github.com/GeertJohan/cgo.wchar/readme.md
new file mode 100644
index 0000000..1be1ef5
--- /dev/null
+++ b/vendor/github.com/GeertJohan/cgo.wchar/readme.md
@@ -0,0 +1,24 @@
+## cgo.wchar
+
+Helps with using wchars with cgo.
+
+### Example
+Example from the go.hid library:
+```go
+func (dev *Device) ManufacturerString() (string, error) {
+ // create WcharString
+ ws := wchar.NewWcharString(100)
+
+ // retrieve manufacturer string from hid
+ res := C.hid_get_manufacturer_string(dev.hidHandle, (*C.wchar_t)(ws.Pointer()), 100)
+ if res != 0 {
+ return "", dev.lastError()
+ }
+
+ // get WcharString as Go string
+ str := ws.GoString()
+
+ // all done
+ return str, nil
+}
+```
diff --git a/vendor/github.com/GeertJohan/cgo.wchar/wchar.go b/vendor/github.com/GeertJohan/cgo.wchar/wchar.go
new file mode 100644
index 0000000..6c0188a
--- /dev/null
+++ b/vendor/github.com/GeertJohan/cgo.wchar/wchar.go
@@ -0,0 +1,159 @@
+package wchar
+
+import (
+ "unsafe"
+)
+
+// return pointer to this Wchar
+func (w Wchar) Pointer() *Wchar {
+ return &w
+}
+
+// convert Wchar to Go rune
+// will return an error when conversion failed.
+func (w Wchar) GoRune() (rune, error) {
+ r, err := convertWcharToGoRune(w)
+ if err != nil {
+ return '\000', err
+ }
+ return r, nil
+}
+
+func FromGoRune(r rune) (Wchar, error) {
+ return convertGoRuneToWchar(r)
+}
+
+// FromWcharPtr converts a *C.wchar_t to a Go Wchar
+func FromWcharPtr(ptr unsafe.Pointer) Wchar {
+ // quick return for null pointer
+ if uintptr(ptr) == 0x0 {
+ return Wchar(0)
+ }
+
+ return *((*Wchar)(ptr))
+}
+
+// go representation of a wchar string (array)
+type WcharString []Wchar
+
+// NewWcharString creates a new WcharString with given length.
+// This is required when the WcharString is being used as write buffer for a call to a C function.
+func NewWcharString(length int) WcharString {
+ return make(WcharString, length)
+}
+
+// FromGoString creates a WcharString from a Go string
+func FromGoString(s string) (WcharString, error) {
+ return convertGoStringToWcharString(s)
+}
+
+// FromWcharStringPtr creates a WcharString from a *C.wchar_t.
+// It finds the end of the *C.wchar_t string by finding the null terminator.
+func FromWcharStringPtr(first unsafe.Pointer) WcharString {
+ // quick return for null pointer
+ if uintptr(first) == 0x0 {
+ return NewWcharString(0)
+ }
+
+ // Get uintptr from first wchar_t
+ wcharPtr := uintptr(first)
+
+ // allocate new WcharString to fill with data. Cap is unknown
+ ws := make(WcharString, 0)
+
+ // append data using pointer arithmic
+ var w Wchar
+ for {
+ // get Wchar value
+ w = *((*Wchar)(unsafe.Pointer(wcharPtr)))
+
+ // check for null byte terminator
+ if w == 0 {
+ break
+ }
+
+ // append Wchar to WcharString
+ ws = append(ws, w)
+
+ // increment pointer 4 bytes
+ wcharPtr += 4
+ }
+
+ // all done
+ return ws
+}
+
+// convert a *C.wchar_t and length int to a WcharString
+func FromWcharStringPtrN(first unsafe.Pointer, length int) WcharString {
+ if uintptr(first) == 0x0 {
+ return NewWcharString(0)
+ }
+
+ // Get uintptr from first wchar_t
+ wcharPtr := uintptr(first)
+
+ // allocate new WcharString to fill with data. Only set cap, later use append
+ ws := make(WcharString, 0, length)
+
+ // append data using pointer arithmic
+ var x Wchar
+ for i := 0; i < length; i++ {
+ // get Wchar
+ x = *((*Wchar)(unsafe.Pointer(wcharPtr)))
+
+ // check for null byte terminator
+ if x == 0 {
+ break
+ }
+
+ // append Wchar to WcharString
+ ws = append(ws, x)
+
+ // increment pointer 4 bytes
+ wcharPtr += 4
+ }
+
+ // all done
+ return ws
+}
+
+// return pointer to first element
+func (ws WcharString) Pointer() *Wchar {
+ return &ws[0]
+}
+
+// convert WcharString to Go string
+// will return an error when conversion failed.
+func (ws WcharString) GoString() (string, error) {
+ str, err := convertWcharStringToGoString(ws)
+ if err != nil {
+ return "", err
+ }
+ return str, nil
+}
+
+// convert a null terminated *C.wchar_t to a Go string
+// convenient wrapper for WcharPtrToWcharString(first).GoString()
+func WcharStringPtrToGoString(first unsafe.Pointer) (string, error) {
+ if uintptr(first) == 0x0 {
+ return "", nil
+ }
+ return convertWcharStringToGoString(FromWcharStringPtr(first))
+}
+
+// convert a *C.wchar_t and length int to a Go string
+// convenient wrapper for WcharPtrIntToWcharString(first, length).GoString()
+func WcharStringPtrNToGoString(first unsafe.Pointer, length int) (string, error) {
+ if uintptr(first) == 0x0 {
+ return "", nil
+ }
+ return convertWcharStringToGoString(FromWcharStringPtrN(first, length))
+}
+
+// convenient wrapper for WcharPtrToWcharString(first).GoString()
+func WcharPtrToGoRune(first unsafe.Pointer) (rune, error) {
+ if uintptr(first) == 0x0 {
+ return '\000', nil
+ }
+ return convertWcharToGoRune(FromWcharPtr(first))
+}
diff --git a/vendor/github.com/GeertJohan/cgo.wchar/wchar_notwin.go b/vendor/github.com/GeertJohan/cgo.wchar/wchar_notwin.go
new file mode 100644
index 0000000..dab4663
--- /dev/null
+++ b/vendor/github.com/GeertJohan/cgo.wchar/wchar_notwin.go
@@ -0,0 +1,6 @@
+// +build !windows
+
+package wchar
+
+// go representation of a wchar
+type Wchar int32
diff --git a/vendor/github.com/GeertJohan/cgo.wchar/wchar_test.go b/vendor/github.com/GeertJohan/cgo.wchar/wchar_test.go
new file mode 100644
index 0000000..4333059
--- /dev/null
+++ b/vendor/github.com/GeertJohan/cgo.wchar/wchar_test.go
@@ -0,0 +1,105 @@
+package wchar
+
+import (
+ "testing"
+)
+
+func TestStringConversion(t *testing.T) {
+ testString := "Iñtërnâtiônàlizætiøn"
+ expectedWcharString := WcharString{
+ 73, 241, 116, 235, 114,
+ 110, 226, 116, 105, 244,
+ 110, 224, 108, 105, 122,
+ 230, 116, 105, 248, 110, 0,
+ }
+
+ w, err := FromGoString(testString)
+ if err != nil {
+ t.Fatalf("Error on conversion. %s", err.Error())
+ }
+
+ if len(w) != len(expectedWcharString) {
+ t.Fatal("Converted string did not match expected WcharString. Lengths are different.")
+ }
+
+ for i := 0; i < len(w); i++ {
+ if w[i] != expectedWcharString[i] {
+ t.Fatalf("Converted string did not match expected WcharString. Fault at position %d. %d!=%d\n", i, w[i], expectedWcharString[i])
+ }
+ }
+}
+
+func TestWcharStringConversion(t *testing.T) {
+ testWcharString := WcharString{
+ 73, 241, 116, 235, 114,
+ 110, 226, 116, 105, 244,
+ 110, 224, 108, 105, 122,
+ 230, 116, 105, 248, 110, 0,
+ }
+ expectedGoString := "Iñtërnâtiônàlizætiøn"
+
+ str, err := testWcharString.GoString()
+ if err != nil {
+ t.Fatalf("Error on conversion. %s", err.Error())
+ }
+
+ if len(str) != len(expectedGoString) {
+ t.Fatal("Converted WcharString did not match expected string. Lengths are different.")
+ }
+
+ for i := 0; i < len(str); i++ {
+ if str[i] != expectedGoString[i] {
+ t.Fatalf("Converted WcharString did not match expected string. Fault at position %d. %d!=%d\n", i, str[i], expectedGoString[i])
+ }
+ }
+}
+
+func TestRuneConversion(t *testing.T) {
+ testRunes := []rune{
+ 'I', 'ñ', 't', 'ë', 'r',
+ 'n', 'â', 't', 'i', 'ô',
+ 'n', 'à', 'l', 'i', 'z',
+ 'æ', 't', 'i', 'ø', 'n',
+ }
+ expectedWchars := []Wchar{
+ 73, 241, 116, 235, 114,
+ 110, 226, 116, 105, 244,
+ 110, 224, 108, 105, 122,
+ 230, 116, 105, 248, 110,
+ }
+
+ for i, testRune := range testRunes {
+ w, err := FromGoRune(testRune)
+ if err != nil {
+ t.Fatalf("Error on conversion. %s", err.Error())
+ }
+ if w != expectedWchars[i] {
+ t.Fatalf("Converted rune did not match expected Wchar. Fault at position %d. %d!=%d\n", i, w, expectedWchars[i])
+ }
+ }
+}
+
+func TestWcharConversion(t *testing.T) {
+ testWchars := []Wchar{
+ 73, 241, 116, 235, 114,
+ 110, 226, 116, 105, 244,
+ 110, 224, 108, 105, 122,
+ 230, 116, 105, 248, 110,
+ }
+ expectedRunes := []rune{
+ 'I', 'ñ', 't', 'ë', 'r',
+ 'n', 'â', 't', 'i', 'ô',
+ 'n', 'à', 'l', 'i', 'z',
+ 'æ', 't', 'i', 'ø', 'n',
+ }
+
+ for i, testWchar := range testWchars {
+ r, err := testWchar.GoRune()
+ if err != nil {
+ t.Fatalf("Error on conversion. %s", err.Error())
+ }
+ if r != expectedRunes[i] {
+ t.Fatalf("Converted Wchar did not match expected rune. Fault at position %d. %d!=%d\n", i, r, expectedRunes[i])
+ }
+ }
+}
diff --git a/vendor/github.com/GeertJohan/cgo.wchar/wchar_windows.go b/vendor/github.com/GeertJohan/cgo.wchar/wchar_windows.go
new file mode 100644
index 0000000..7c7c930
--- /dev/null
+++ b/vendor/github.com/GeertJohan/cgo.wchar/wchar_windows.go
@@ -0,0 +1,4 @@
+package wchar
+
+// go representation of a wchar
+type Wchar uint16