mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
accounts/usbwallet: add missing components in vendor
This commit is contained in:
parent
6edbfc23fd
commit
9133bc851c
5 changed files with 693 additions and 0 deletions
194
vendor/github.com/trezor/trezord-go/memorywriter/memorywriter.go
generated
vendored
Normal file
194
vendor/github.com/trezor/trezord-go/memorywriter/memorywriter.go
generated
vendored
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
package memorywriter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// This is a helper package that writes logs to memory,
|
||||
// rotates the lines, but remembers some lines on the start
|
||||
// It is useful for detailed logging, that would take too much memory
|
||||
|
||||
// to prevent possible memory issues, hardcode max line length
|
||||
const maxLineLength = 500
|
||||
|
||||
type MemoryWriter struct {
|
||||
maxLineCount int
|
||||
lines [][]byte // lines include newlines
|
||||
startCount int
|
||||
startLines [][]byte
|
||||
startTime time.Time
|
||||
printTime bool
|
||||
mutex sync.Mutex
|
||||
|
||||
outWriter io.Writer
|
||||
}
|
||||
|
||||
func findInternalPrefix() string {
|
||||
pc := make([]uintptr, 15)
|
||||
n := runtime.Callers(1, pc)
|
||||
frames := runtime.CallersFrames(pc[:n])
|
||||
frame, _ := frames.Next()
|
||||
file := frame.File
|
||||
return strings.TrimSuffix(file, "memorywriter/memorywriter.go")
|
||||
}
|
||||
|
||||
var internalPrefix = findInternalPrefix()
|
||||
|
||||
func (m *MemoryWriter) Log(s string) {
|
||||
pc := make([]uintptr, 15)
|
||||
n := runtime.Callers(2, pc)
|
||||
frames := runtime.CallersFrames(pc[:n])
|
||||
frame, _ := frames.Next()
|
||||
file := frame.File
|
||||
file = strings.TrimPrefix(file, internalPrefix)
|
||||
function := frame.Function
|
||||
function = strings.TrimPrefix(function, "github.com/trezor/trezord-go/")
|
||||
r := fmt.Sprintf("[%s %d %s]", file, frame.Line, function)
|
||||
m.println(r + " " + s)
|
||||
|
||||
}
|
||||
|
||||
func (m *MemoryWriter) println(s string) {
|
||||
long := []byte(s + "\n")
|
||||
_, err := m.Write(long)
|
||||
if err != nil {
|
||||
// give up, just print on stdout
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Writer remembers lines in memory
|
||||
func (m *MemoryWriter) Write(p []byte) (int, error) {
|
||||
m.mutex.Lock()
|
||||
defer func() {
|
||||
m.mutex.Unlock()
|
||||
}()
|
||||
if len(p) > maxLineLength {
|
||||
return 0, errors.New("input too long")
|
||||
}
|
||||
|
||||
var newline []byte
|
||||
if !m.printTime {
|
||||
newline = make([]byte, len(p))
|
||||
copy(newline, p)
|
||||
} else {
|
||||
now := time.Now()
|
||||
elapsed := now.Sub(m.startTime)
|
||||
|
||||
elapsedS := fmt.Sprintf("%.6f", elapsed.Seconds())
|
||||
nowS := now.Format("15:04:05")
|
||||
|
||||
newline = []byte(fmt.Sprintf("[%s : %s] %s", elapsedS, nowS, string(p)))
|
||||
}
|
||||
|
||||
if len(m.startLines) < m.startCount {
|
||||
// do not rotate
|
||||
m.startLines = append(m.startLines, newline)
|
||||
} else {
|
||||
// rotate
|
||||
for len(m.lines) >= m.maxLineCount {
|
||||
m.lines = m.lines[1:]
|
||||
}
|
||||
|
||||
m.lines = append(m.lines, newline)
|
||||
}
|
||||
if m.outWriter != nil {
|
||||
_, wrErr := m.outWriter.Write(newline)
|
||||
if wrErr != nil {
|
||||
// give up, just print on stdout
|
||||
fmt.Println(wrErr)
|
||||
}
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Exports lines to a writer, plus adds additional text on top
|
||||
// In our case, additional text is devcon exports and trezord version
|
||||
func (m *MemoryWriter) writeTo(start string, w io.Writer) error {
|
||||
m.mutex.Lock()
|
||||
defer func() {
|
||||
m.mutex.Unlock()
|
||||
}()
|
||||
_, err := w.Write([]byte(start))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write end lines (latest on up)
|
||||
for i := len(m.lines) - 1; i >= 0; i-- {
|
||||
line := m.lines[i]
|
||||
_, err = w.Write(line)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// ... to make space between start and end
|
||||
_, err = w.Write([]byte("...\n"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write start lines
|
||||
for i := len(m.startLines) - 1; i >= 0; i-- {
|
||||
line := m.startLines[i]
|
||||
_, err = w.Write(line)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String exports as string
|
||||
func (m *MemoryWriter) String(start string) (string, error) {
|
||||
var b bytes.Buffer
|
||||
err := m.writeTo(start, &b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return b.String(), nil
|
||||
}
|
||||
|
||||
// Gzip exports as GZip bytes
|
||||
func (m *MemoryWriter) Gzip(start string) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
gw, err := gzip.NewWriterLevel(&buf, gzip.BestCompression)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gw.Name = "log.txt"
|
||||
err = m.writeTo(start, gw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = gw.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func New(size int, startSize int, printTime bool, out io.Writer) *MemoryWriter {
|
||||
return &MemoryWriter{
|
||||
maxLineCount: size,
|
||||
lines: make([][]byte, 0, size),
|
||||
startCount: startSize,
|
||||
startLines: make([][]byte, 0, startSize),
|
||||
startTime: time.Now(),
|
||||
printTime: printTime,
|
||||
outWriter: out,
|
||||
}
|
||||
}
|
||||
14
vendor/github.com/trezor/trezord-go/usb/lowlevel/hidapi/README.md
generated
vendored
Normal file
14
vendor/github.com/trezor/trezord-go/usb/lowlevel/hidapi/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# hidapi go wrapper
|
||||
|
||||
This is a go wrapper around hidapi.
|
||||
|
||||
The code is mostly copied from https://github.com/karalabe/hid
|
||||
|
||||
ALSO NOTE - there is a hardcoded device filter because of random windows errors.
|
||||
|
||||
## License
|
||||
|
||||
Code is under GNU LGPL 2.1.
|
||||
|
||||
* (C) Karel Bilek 2017
|
||||
* (C) 2017 Péter Szilágyi (also see https://github.com/karalabe/hid for comprehensive list)
|
||||
238
vendor/github.com/trezor/trezord-go/usb/lowlevel/hidapi/hid.go
generated
vendored
Normal file
238
vendor/github.com/trezor/trezord-go/usb/lowlevel/hidapi/hid.go
generated
vendored
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
// hid - Gopher Interface Devices (USB HID)
|
||||
// Copyright (c) 2017 Péter Szilágyi. All rights reserved.
|
||||
//
|
||||
// This file is released under the 3-clause BSD license. Note however that Linux
|
||||
// support depends on libusb, released under GNU LGPL 2.1 or later.
|
||||
|
||||
// Package hid provides an interface for USB HID devices.
|
||||
|
||||
// +build darwin,!ios,cgo windows,cgo
|
||||
|
||||
package hidapi
|
||||
|
||||
/*
|
||||
extern void goHidLog(const char *s);
|
||||
|
||||
#cgo CFLAGS: -I./c
|
||||
|
||||
#cgo darwin CFLAGS: -DOS_DARWIN
|
||||
#cgo darwin LDFLAGS: -framework CoreFoundation -framework IOKit
|
||||
#cgo windows CFLAGS: -DOS_WINDOWS
|
||||
#cgo windows LDFLAGS: -lsetupapi
|
||||
|
||||
#ifdef OS_DARWIN
|
||||
#include "mac/hid.c"
|
||||
#elif OS_WINDOWS
|
||||
#define HARDCODED_HIDAPI_DEVICE_FILTER "vid_534c"
|
||||
#include "windows/hid.c"
|
||||
#endif
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// ErrDeviceClosed is returned for operations where the device closed before or
|
||||
// during the execution.
|
||||
var ErrDeviceClosed = errors.New("hid: device closed")
|
||||
|
||||
// ErrUnsupportedPlatform is returned for all operations where the underlying
|
||||
// operating system is not supported by the library.
|
||||
var ErrUnsupportedPlatform = errors.New("hid: unsupported platform")
|
||||
|
||||
// HidDeviceInfo is a hidapi info structure.
|
||||
type HidDeviceInfo struct {
|
||||
Path string // Platform-specific device path
|
||||
VendorID uint16 // Device Vendor ID
|
||||
ProductID uint16 // Device Product ID
|
||||
Release uint16 // Device Release Number in binary-coded decimal, also known as Device Version Number
|
||||
Serial string // Serial Number
|
||||
Manufacturer string // Manufacturer String
|
||||
Product string // Product string
|
||||
UsagePage uint16 // Usage Page for this Device/Interface (Windows/Mac only)
|
||||
Usage uint16 // Usage for this Device/Interface (Windows/Mac only)
|
||||
|
||||
// The USB interface which this logical device
|
||||
// represents. Valid on both Linux implementations
|
||||
// in all cases, and valid on the Windows implementation
|
||||
// only if the device contains more than one interface.
|
||||
Interface int
|
||||
}
|
||||
|
||||
// enumerateLock is a mutex serializing access to USB device enumeration needed
|
||||
// by the macOS USB HID system calls, which require 2 consecutive method calls
|
||||
// for enumeration, causing crashes if called concurrently.
|
||||
//
|
||||
// For more details, see:
|
||||
// https://developer.apple.com/documentation/iokit/1438371-iohidmanagersetdevicematching
|
||||
// > "subsequent calls will cause the hid manager to release previously enumerated devices"
|
||||
var enumerateLock sync.Mutex
|
||||
|
||||
func init() {
|
||||
// Initialize the HIDAPI library
|
||||
C.hid_init()
|
||||
}
|
||||
|
||||
// Enumerate returns a list of all the HID devices attached to the system which
|
||||
// match the vendor and product id:
|
||||
// - If the vendor id is set to 0 then any vendor matches.
|
||||
// - If the product id is set to 0 then any product matches.
|
||||
// - If the vendor and product id are both 0, all HID devices are returned.
|
||||
func HidEnumerate(vendorID uint16, productID uint16) []HidDeviceInfo {
|
||||
enumerateLock.Lock()
|
||||
defer enumerateLock.Unlock()
|
||||
|
||||
// Gather all device infos and ensure they are freed before returning
|
||||
head := C.hid_enumerate(C.ushort(vendorID), C.ushort(productID))
|
||||
if head == nil {
|
||||
return nil
|
||||
}
|
||||
defer C.hid_free_enumeration(head)
|
||||
|
||||
// Iterate the list and retrieve the device details
|
||||
var infos []HidDeviceInfo
|
||||
for ; head != nil; head = head.next {
|
||||
info := HidDeviceInfo{
|
||||
Path: C.GoString(head.path),
|
||||
VendorID: uint16(head.vendor_id),
|
||||
ProductID: uint16(head.product_id),
|
||||
Release: uint16(head.release_number),
|
||||
UsagePage: uint16(head.usage_page),
|
||||
Usage: uint16(head.usage),
|
||||
Interface: int(head.interface_number),
|
||||
}
|
||||
if head.serial_number != nil {
|
||||
info.Serial, _ = wcharTToString(head.serial_number)
|
||||
}
|
||||
if head.product_string != nil {
|
||||
info.Product, _ = wcharTToString(head.product_string)
|
||||
}
|
||||
if head.manufacturer_string != nil {
|
||||
info.Manufacturer, _ = wcharTToString(head.manufacturer_string)
|
||||
}
|
||||
infos = append(infos, info)
|
||||
}
|
||||
return infos
|
||||
}
|
||||
|
||||
// Open connects to an HID device by its path name.
|
||||
func (info HidDeviceInfo) Open() (*HidDevice, error) {
|
||||
path := C.CString(info.Path)
|
||||
defer C.free(unsafe.Pointer(path))
|
||||
|
||||
device := C.hid_open_path(path)
|
||||
if device == nil {
|
||||
return nil, errors.New("hidapi: failed to open device")
|
||||
}
|
||||
return &HidDevice{
|
||||
HidDeviceInfo: info,
|
||||
device: device,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Device is a live HID USB connected device handle.
|
||||
type HidDevice struct {
|
||||
HidDeviceInfo // Embed the infos for easier access
|
||||
|
||||
device *C.hid_device // Low level HID device to communicate through
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// Close releases the HID USB device handle.
|
||||
func (dev *HidDevice) Close() error {
|
||||
dev.lock.Lock()
|
||||
defer dev.lock.Unlock()
|
||||
|
||||
if dev.device != nil {
|
||||
C.hid_close(dev.device)
|
||||
dev.device = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write sends an output report to a HID device.
|
||||
//
|
||||
// Write will send the data on the first OUT endpoint, if one exists. If it does
|
||||
// not, it will send the data through the Control Endpoint (Endpoint 0).
|
||||
func (dev *HidDevice) Write(b []byte, prepend bool) (int, error) {
|
||||
// Abort if nothing to write
|
||||
if len(b) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
// Abort if device closed in between
|
||||
dev.lock.Lock()
|
||||
device := dev.device
|
||||
dev.lock.Unlock()
|
||||
|
||||
if device == nil {
|
||||
return 0, ErrDeviceClosed
|
||||
}
|
||||
// Prepend a HID report ID on Windows, other OSes don't need it
|
||||
var report []byte
|
||||
if prepend && runtime.GOOS == "windows" {
|
||||
report = append([]byte{0x00}, b...)
|
||||
} else {
|
||||
report = b
|
||||
}
|
||||
// Execute the write operation
|
||||
written := int(C.hid_write(device, (*C.uchar)(&report[0]), C.size_t(len(report))))
|
||||
if written == -1 {
|
||||
// If the write failed, verify if closed or other error
|
||||
dev.lock.Lock()
|
||||
device = dev.device
|
||||
dev.lock.Unlock()
|
||||
|
||||
if device == nil {
|
||||
return 0, ErrDeviceClosed
|
||||
}
|
||||
// Device not closed, some other error occurred
|
||||
message := C.hid_error(device)
|
||||
if message == nil {
|
||||
return 0, errors.New("hidapi: unknown failure")
|
||||
}
|
||||
failure, _ := wcharTToString(message)
|
||||
return 0, errors.New("hidapi: " + failure)
|
||||
}
|
||||
return written, nil
|
||||
}
|
||||
|
||||
// Read retrieves an input report from a HID device.
|
||||
func (dev *HidDevice) Read(b []byte, milliseconds int) (int, error) {
|
||||
// Aborth if nothing to read
|
||||
if len(b) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
// Abort if device closed in between
|
||||
dev.lock.Lock()
|
||||
device := dev.device
|
||||
dev.lock.Unlock()
|
||||
|
||||
if device == nil {
|
||||
return 0, ErrDeviceClosed
|
||||
}
|
||||
// Execute the read operation
|
||||
read := int(C.hid_read_timeout(device, (*C.uchar)(&b[0]), C.size_t(len(b)), C.int(milliseconds)))
|
||||
if read == -1 {
|
||||
// If the read failed, verify if closed or other error
|
||||
dev.lock.Lock()
|
||||
device = dev.device
|
||||
dev.lock.Unlock()
|
||||
|
||||
if device == nil {
|
||||
return 0, ErrDeviceClosed
|
||||
}
|
||||
// Device not closed, some other error occurred
|
||||
message := C.hid_error(device)
|
||||
if message == nil {
|
||||
return 0, errors.New("hidapi: unknown failure")
|
||||
}
|
||||
failure, _ := wcharTToString(message)
|
||||
return 0, errors.New("hidapi: " + failure)
|
||||
}
|
||||
return read, nil
|
||||
}
|
||||
20
vendor/github.com/trezor/trezord-go/usb/lowlevel/hidapi/log.go
generated
vendored
Normal file
20
vendor/github.com/trezor/trezord-go/usb/lowlevel/hidapi/log.go
generated
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package hidapi
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
import "C"
|
||||
|
||||
var writer io.Writer
|
||||
|
||||
func SetLogWriter(l io.Writer) {
|
||||
writer = l
|
||||
}
|
||||
|
||||
//export goHidLog
|
||||
func goHidLog(s *C.char) {
|
||||
if writer != nil {
|
||||
writer.Write([]byte(C.GoString(s)))
|
||||
}
|
||||
}
|
||||
227
vendor/github.com/trezor/trezord-go/usb/lowlevel/hidapi/wchar.go
generated
vendored
Normal file
227
vendor/github.com/trezor/trezord-go/usb/lowlevel/hidapi/wchar.go
generated
vendored
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
// This file is https://github.com/orofarne/gowchar/blob/master/gowchar.go
|
||||
//
|
||||
// It was vendored inline to work around CGO limitations that don't allow C types
|
||||
// to directly cross package API boundaries.
|
||||
//
|
||||
// The vendored file is licensed under the 3-clause BSD license, according to:
|
||||
// https://github.com/orofarne/gowchar/blob/master/LICENSE
|
||||
|
||||
// +build !ios
|
||||
// +build linux freebsd darwin windows
|
||||
|
||||
package hidapi
|
||||
|
||||
/*
|
||||
#include <wchar.h>
|
||||
|
||||
const size_t SIZEOF_WCHAR_T = sizeof(wchar_t);
|
||||
|
||||
void gowchar_set (wchar_t *arr, int pos, wchar_t val)
|
||||
{
|
||||
arr[pos] = val;
|
||||
}
|
||||
|
||||
wchar_t gowchar_get (wchar_t *arr, int pos)
|
||||
{
|
||||
return arr[pos];
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unicode/utf16"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var sizeofWcharT C.size_t = C.size_t(C.SIZEOF_WCHAR_T)
|
||||
|
||||
func stringToWcharT(s string) (*C.wchar_t, C.size_t) {
|
||||
switch sizeofWcharT {
|
||||
case 2:
|
||||
return stringToWchar2(s) // Windows
|
||||
case 4:
|
||||
return stringToWchar4(s) // Unix
|
||||
default:
|
||||
panic(fmt.Sprintf("Invalid sizeof(wchar_t) = %v", sizeofWcharT))
|
||||
}
|
||||
}
|
||||
|
||||
func wcharTToString(s *C.wchar_t) (string, error) {
|
||||
switch sizeofWcharT {
|
||||
case 2:
|
||||
return wchar2ToString(s) // Windows
|
||||
case 4:
|
||||
return wchar4ToString(s) // Unix
|
||||
default:
|
||||
panic(fmt.Sprintf("Invalid sizeof(wchar_t) = %v", sizeofWcharT))
|
||||
}
|
||||
}
|
||||
|
||||
func wcharTNToString(s *C.wchar_t, size C.size_t) (string, error) {
|
||||
switch sizeofWcharT {
|
||||
case 2:
|
||||
return wchar2NToString(s, size) // Windows
|
||||
case 4:
|
||||
return wchar4NToString(s, size) // Unix
|
||||
default:
|
||||
panic(fmt.Sprintf("Invalid sizeof(wchar_t) = %v", sizeofWcharT))
|
||||
}
|
||||
}
|
||||
|
||||
// Windows
|
||||
func stringToWchar2(s string) (*C.wchar_t, C.size_t) {
|
||||
var slen int
|
||||
s1 := s
|
||||
for len(s1) > 0 {
|
||||
r, size := utf8.DecodeRuneInString(s1)
|
||||
if er, _ := utf16.EncodeRune(r); er == '\uFFFD' {
|
||||
slen += 1
|
||||
} else {
|
||||
slen += 2
|
||||
}
|
||||
s1 = s1[size:]
|
||||
}
|
||||
slen++ // \0
|
||||
res := C.malloc(C.size_t(slen) * sizeofWcharT)
|
||||
var i int
|
||||
for len(s) > 0 {
|
||||
r, size := utf8.DecodeRuneInString(s)
|
||||
if r1, r2 := utf16.EncodeRune(r); r1 != '\uFFFD' {
|
||||
C.gowchar_set((*C.wchar_t)(res), C.int(i), C.wchar_t(r1))
|
||||
i++
|
||||
C.gowchar_set((*C.wchar_t)(res), C.int(i), C.wchar_t(r2))
|
||||
i++
|
||||
} else {
|
||||
C.gowchar_set((*C.wchar_t)(res), C.int(i), C.wchar_t(r))
|
||||
i++
|
||||
}
|
||||
s = s[size:]
|
||||
}
|
||||
C.gowchar_set((*C.wchar_t)(res), C.int(slen-1), C.wchar_t(0)) // \0
|
||||
return (*C.wchar_t)(res), C.size_t(slen)
|
||||
}
|
||||
|
||||
// Unix
|
||||
func stringToWchar4(s string) (*C.wchar_t, C.size_t) {
|
||||
slen := utf8.RuneCountInString(s)
|
||||
slen++ // \0
|
||||
res := C.malloc(C.size_t(slen) * sizeofWcharT)
|
||||
var i int
|
||||
for len(s) > 0 {
|
||||
r, size := utf8.DecodeRuneInString(s)
|
||||
C.gowchar_set((*C.wchar_t)(res), C.int(i), C.wchar_t(r))
|
||||
s = s[size:]
|
||||
i++
|
||||
}
|
||||
C.gowchar_set((*C.wchar_t)(res), C.int(slen-1), C.wchar_t(0)) // \0
|
||||
return (*C.wchar_t)(res), C.size_t(slen)
|
||||
}
|
||||
|
||||
// Windows
|
||||
func wchar2ToString(s *C.wchar_t) (string, error) {
|
||||
var i int
|
||||
var res string
|
||||
for {
|
||||
ch := C.gowchar_get(s, C.int(i))
|
||||
if ch == 0 {
|
||||
break
|
||||
}
|
||||
r := rune(ch)
|
||||
i++
|
||||
if !utf16.IsSurrogate(r) {
|
||||
if !utf8.ValidRune(r) {
|
||||
err := fmt.Errorf("Invalid rune at position %v", i)
|
||||
return "", err
|
||||
}
|
||||
res += string(r)
|
||||
} else {
|
||||
ch2 := C.gowchar_get(s, C.int(i))
|
||||
r2 := rune(ch2)
|
||||
r12 := utf16.DecodeRune(r, r2)
|
||||
if r12 == '\uFFFD' {
|
||||
err := fmt.Errorf("Invalid surrogate pair at position %v", i-1)
|
||||
return "", err
|
||||
}
|
||||
res += string(r12)
|
||||
i++
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Unix
|
||||
func wchar4ToString(s *C.wchar_t) (string, error) {
|
||||
var i int
|
||||
var res string
|
||||
for {
|
||||
ch := C.gowchar_get(s, C.int(i))
|
||||
if ch == 0 {
|
||||
break
|
||||
}
|
||||
r := rune(ch)
|
||||
if !utf8.ValidRune(r) {
|
||||
err := fmt.Errorf("Invalid rune at position %v", i)
|
||||
return "", err
|
||||
}
|
||||
res += string(r)
|
||||
i++
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Windows
|
||||
func wchar2NToString(s *C.wchar_t, size C.size_t) (string, error) {
|
||||
var i int
|
||||
var res string
|
||||
N := int(size)
|
||||
for i < N {
|
||||
ch := C.gowchar_get(s, C.int(i))
|
||||
if ch == 0 {
|
||||
break
|
||||
}
|
||||
r := rune(ch)
|
||||
i++
|
||||
if !utf16.IsSurrogate(r) {
|
||||
if !utf8.ValidRune(r) {
|
||||
err := fmt.Errorf("Invalid rune at position %v", i)
|
||||
return "", err
|
||||
}
|
||||
|
||||
res += string(r)
|
||||
} else {
|
||||
if i >= N {
|
||||
err := fmt.Errorf("Invalid surrogate pair at position %v", i-1)
|
||||
return "", err
|
||||
}
|
||||
ch2 := C.gowchar_get(s, C.int(i))
|
||||
r2 := rune(ch2)
|
||||
r12 := utf16.DecodeRune(r, r2)
|
||||
if r12 == '\uFFFD' {
|
||||
err := fmt.Errorf("Invalid surrogate pair at position %v", i-1)
|
||||
return "", err
|
||||
}
|
||||
res += string(r12)
|
||||
i++
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Unix
|
||||
func wchar4NToString(s *C.wchar_t, size C.size_t) (string, error) {
|
||||
var i int
|
||||
var res string
|
||||
N := int(size)
|
||||
for i < N {
|
||||
ch := C.gowchar_get(s, C.int(i))
|
||||
r := rune(ch)
|
||||
if !utf8.ValidRune(r) {
|
||||
err := fmt.Errorf("Invalid rune at position %v", i)
|
||||
return "", err
|
||||
}
|
||||
res += string(r)
|
||||
i++
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
Loading…
Reference in a new issue