From 20ccf7331188c5ddfe5db30ea5f90c45319e4fb8 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Mon, 4 Sep 2017 09:45:22 +0200 Subject: Add vendor --- vendor/github.com/GeertJohan/cgo.wchar/convert.go | 274 +++++++++++++++++++++ vendor/github.com/GeertJohan/cgo.wchar/readme.md | 24 ++ vendor/github.com/GeertJohan/cgo.wchar/wchar.go | 159 ++++++++++++ .../GeertJohan/cgo.wchar/wchar_notwin.go | 6 + .../github.com/GeertJohan/cgo.wchar/wchar_test.go | 105 ++++++++ .../GeertJohan/cgo.wchar/wchar_windows.go | 4 + 6 files changed, 572 insertions(+) create mode 100644 vendor/github.com/GeertJohan/cgo.wchar/convert.go create mode 100644 vendor/github.com/GeertJohan/cgo.wchar/readme.md create mode 100644 vendor/github.com/GeertJohan/cgo.wchar/wchar.go create mode 100644 vendor/github.com/GeertJohan/cgo.wchar/wchar_notwin.go create mode 100644 vendor/github.com/GeertJohan/cgo.wchar/wchar_test.go create mode 100644 vendor/github.com/GeertJohan/cgo.wchar/wchar_windows.go (limited to 'vendor/github.com/GeertJohan/cgo.wchar') 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 +#ifdef __APPLE__ +# define LIBICONV_PLUG 1 +#endif +#include +#include +*/ +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 -- cgit v1.2.3