aboutsummaryrefslogtreecommitdiffstats
path: root/vendor
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2019-06-04 23:06:11 +0800
committerGitHub <noreply@github.com>2019-06-04 23:06:11 +0800
commitde38a1dbd429df258c43d93c7f24dc6591d0ab39 (patch)
treeafa0211bcff8daf3d658a99b789d77f51cc90480 /vendor
parent42b81f94adba9aae7f7727951f35e92184b1eedb (diff)
parent5d68400cad8cda3b265d2bc9d45223b303349023 (diff)
downloadgo-tangerine-de38a1dbd429df258c43d93c7f24dc6591d0ab39.tar
go-tangerine-de38a1dbd429df258c43d93c7f24dc6591d0ab39.tar.gz
go-tangerine-de38a1dbd429df258c43d93c7f24dc6591d0ab39.tar.bz2
go-tangerine-de38a1dbd429df258c43d93c7f24dc6591d0ab39.tar.lz
go-tangerine-de38a1dbd429df258c43d93c7f24dc6591d0ab39.tar.xz
go-tangerine-de38a1dbd429df258c43d93c7f24dc6591d0ab39.tar.zst
go-tangerine-de38a1dbd429df258c43d93c7f24dc6591d0ab39.zip
Merge pull request #19588 from gballet/trezor-fix-ownlib
accounts/usbwallet: add webusb trezor support
Diffstat (limited to 'vendor')
-rw-r--r--vendor/github.com/golang/protobuf/LICENSE3
-rw-r--r--vendor/github.com/golang/protobuf/proto/Makefile43
-rw-r--r--vendor/github.com/golang/protobuf/proto/clone.go46
-rw-r--r--vendor/github.com/golang/protobuf/proto/decode.go669
-rw-r--r--vendor/github.com/golang/protobuf/proto/deprecated.go63
-rw-r--r--vendor/github.com/golang/protobuf/proto/discard.go350
-rw-r--r--vendor/github.com/golang/protobuf/proto/encode.go1209
-rw-r--r--vendor/github.com/golang/protobuf/proto/equal.go33
-rw-r--r--vendor/github.com/golang/protobuf/proto/extensions.go282
-rw-r--r--vendor/github.com/golang/protobuf/proto/lib.go166
-rw-r--r--vendor/github.com/golang/protobuf/proto/message_set.go138
-rw-r--r--vendor/github.com/golang/protobuf/proto/pointer_reflect.go598
-rw-r--r--vendor/github.com/golang/protobuf/proto/pointer_unsafe.go377
-rw-r--r--vendor/github.com/golang/protobuf/proto/properties.go476
-rw-r--r--vendor/github.com/golang/protobuf/proto/table_marshal.go2776
-rw-r--r--vendor/github.com/golang/protobuf/proto/table_merge.go654
-rw-r--r--vendor/github.com/golang/protobuf/proto/table_unmarshal.go2053
-rw-r--r--vendor/github.com/golang/protobuf/proto/text.go65
-rw-r--r--vendor/github.com/golang/protobuf/proto/text_parser.go83
-rw-r--r--vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile36
-rw-r--r--vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go1445
-rw-r--r--vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto883
-rw-r--r--vendor/github.com/karalabe/hid/LICENSE.md8
-rw-r--r--vendor/github.com/karalabe/hid/README.md53
-rw-r--r--vendor/github.com/karalabe/hid/hid.go37
-rw-r--r--vendor/github.com/karalabe/hid/hid_disabled.go51
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.c728
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.h55
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.c259
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.h63
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.c4290
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/version_nano.h1
-rw-r--r--vendor/github.com/karalabe/usb/AUTHORS6
-rw-r--r--vendor/github.com/karalabe/usb/LICENSE165
-rw-r--r--vendor/github.com/karalabe/usb/README.md47
-rw-r--r--vendor/github.com/karalabe/usb/appveyor.yml (renamed from vendor/github.com/karalabe/hid/appveyor.yml)6
-rw-r--r--vendor/github.com/karalabe/usb/demo.go76
-rw-r--r--vendor/github.com/karalabe/usb/go.mod3
-rw-r--r--vendor/github.com/karalabe/usb/hid_disabled.go42
-rw-r--r--vendor/github.com/karalabe/usb/hid_enabled.go (renamed from vendor/github.com/karalabe/hid/hid_enabled.go)99
-rw-r--r--vendor/github.com/karalabe/usb/hidapi/AUTHORS.txt (renamed from vendor/github.com/karalabe/hid/hidapi/AUTHORS.txt)0
-rw-r--r--vendor/github.com/karalabe/usb/hidapi/LICENSE-bsd.txt (renamed from vendor/github.com/karalabe/hid/hidapi/LICENSE-bsd.txt)0
-rw-r--r--vendor/github.com/karalabe/usb/hidapi/LICENSE-gpl3.txt (renamed from vendor/github.com/karalabe/hid/hidapi/LICENSE-gpl3.txt)0
-rw-r--r--vendor/github.com/karalabe/usb/hidapi/LICENSE-orig.txt (renamed from vendor/github.com/karalabe/hid/hidapi/LICENSE-orig.txt)0
-rw-r--r--vendor/github.com/karalabe/usb/hidapi/LICENSE.txt (renamed from vendor/github.com/karalabe/hid/hidapi/LICENSE.txt)0
-rw-r--r--vendor/github.com/karalabe/usb/hidapi/README.txt (renamed from vendor/github.com/karalabe/hid/hidapi/README.txt)0
-rw-r--r--vendor/github.com/karalabe/usb/hidapi/hidapi/hidapi.h (renamed from vendor/github.com/karalabe/hid/hidapi/hidapi/hidapi.h)0
-rw-r--r--vendor/github.com/karalabe/usb/hidapi/libusb/hid.c (renamed from vendor/github.com/karalabe/hid/hidapi/libusb/hid.c)0
-rw-r--r--vendor/github.com/karalabe/usb/hidapi/mac/hid.c (renamed from vendor/github.com/karalabe/hid/hidapi/mac/hid.c)0
-rw-r--r--[-rwxr-xr-x]vendor/github.com/karalabe/usb/hidapi/windows/hid.c (renamed from vendor/github.com/karalabe/hid/hidapi/windows/hid.c)0
-rw-r--r--vendor/github.com/karalabe/usb/libs.go74
-rw-r--r--vendor/github.com/karalabe/usb/libusb/AUTHORS (renamed from vendor/github.com/karalabe/hid/libusb/AUTHORS)34
-rw-r--r--vendor/github.com/karalabe/usb/libusb/COPYING (renamed from vendor/github.com/karalabe/hid/libusb/COPYING)0
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/config.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/config.h)0
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/core.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/core.c)346
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/descriptor.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/descriptor.c)21
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/hotplug.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/hotplug.c)123
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/hotplug.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/hotplug.h)59
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/io.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/io.c)73
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/libusb.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/libusb.h)95
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/libusbi.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/libusbi.h)162
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/darwin_usb.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.c)102
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/darwin_usb.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.h)61
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_pollfs.cpp (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_pollfs.cpp)0
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb.h)0
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_backend.cpp (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_backend.cpp)0
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_raw.cpp (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.cpp)7
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_raw.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.h)0
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/linux_netlink.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/linux_netlink.c)65
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/linux_udev.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/linux_udev.c)34
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/linux_usbfs.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.c)262
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/linux_usbfs.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.h)3
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/netbsd_usb.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/netbsd_usb.c)6
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/openbsd_usb.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/openbsd_usb.c)6
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/poll_posix.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.c)41
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/poll_posix.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.h)0
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.c364
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.h)52
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/sunos_usb.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.c)567
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/sunos_usb.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.h)6
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.c)11
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.h102
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.c126
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.h)93
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/wince_usb.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.c)67
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/wince_usb.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.h)0
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/windows_common.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/windows_common.h)36
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.c)629
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.h110
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_shared_types.h138
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/windows_usbdk.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.c)417
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/windows_usbdk.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.h)49
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.c3009
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.h)593
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/strerror.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/strerror.c)0
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/sync.c (renamed from vendor/github.com/karalabe/hid/libusb/libusb/sync.c)0
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/version.h (renamed from vendor/github.com/karalabe/hid/libusb/libusb/version.h)2
-rw-r--r--vendor/github.com/karalabe/usb/libusb/libusb/version_nano.h1
-rw-r--r--vendor/github.com/karalabe/usb/raw_disabled.go42
-rw-r--r--vendor/github.com/karalabe/usb/raw_enabled.go253
-rw-r--r--vendor/github.com/karalabe/usb/raw_errors.go74
-rw-r--r--vendor/github.com/karalabe/usb/usb.go68
-rw-r--r--vendor/github.com/karalabe/usb/usb_disabled.go46
-rw-r--r--vendor/github.com/karalabe/usb/usb_enabled.go98
-rw-r--r--vendor/github.com/karalabe/usb/wchar.go (renamed from vendor/github.com/karalabe/hid/wchar.go)4
-rw-r--r--vendor/vendor.json20
106 files changed, 16163 insertions, 10825 deletions
diff --git a/vendor/github.com/golang/protobuf/LICENSE b/vendor/github.com/golang/protobuf/LICENSE
index 1b1b1921e..0f646931a 100644
--- a/vendor/github.com/golang/protobuf/LICENSE
+++ b/vendor/github.com/golang/protobuf/LICENSE
@@ -1,7 +1,4 @@
-Go support for Protocol Buffers - Google's data interchange format
-
Copyright 2010 The Go Authors. All rights reserved.
-https://github.com/golang/protobuf
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
diff --git a/vendor/github.com/golang/protobuf/proto/Makefile b/vendor/github.com/golang/protobuf/proto/Makefile
deleted file mode 100644
index e2e0651a9..000000000
--- a/vendor/github.com/golang/protobuf/proto/Makefile
+++ /dev/null
@@ -1,43 +0,0 @@
-# Go support for Protocol Buffers - Google's data interchange format
-#
-# Copyright 2010 The Go Authors. All rights reserved.
-# https://github.com/golang/protobuf
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-install:
- go install
-
-test: install generate-test-pbs
- go test
-
-
-generate-test-pbs:
- make install
- make -C testdata
- protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto
- make
diff --git a/vendor/github.com/golang/protobuf/proto/clone.go b/vendor/github.com/golang/protobuf/proto/clone.go
index e392575b3..3cd3249f7 100644
--- a/vendor/github.com/golang/protobuf/proto/clone.go
+++ b/vendor/github.com/golang/protobuf/proto/clone.go
@@ -35,22 +35,39 @@
package proto
import (
+ "fmt"
"log"
"reflect"
"strings"
)
// Clone returns a deep copy of a protocol buffer.
-func Clone(pb Message) Message {
- in := reflect.ValueOf(pb)
+func Clone(src Message) Message {
+ in := reflect.ValueOf(src)
if in.IsNil() {
- return pb
+ return src
}
-
out := reflect.New(in.Type().Elem())
- // out is empty so a merge is a deep copy.
- mergeStruct(out.Elem(), in.Elem())
- return out.Interface().(Message)
+ dst := out.Interface().(Message)
+ Merge(dst, src)
+ return dst
+}
+
+// Merger is the interface representing objects that can merge messages of the same type.
+type Merger interface {
+ // Merge merges src into this message.
+ // Required and optional fields that are set in src will be set to that value in dst.
+ // Elements of repeated fields will be appended.
+ //
+ // Merge may panic if called with a different argument type than the receiver.
+ Merge(src Message)
+}
+
+// generatedMerger is the custom merge method that generated protos will have.
+// We must add this method since a generate Merge method will conflict with
+// many existing protos that have a Merge data field already defined.
+type generatedMerger interface {
+ XXX_Merge(src Message)
}
// Merge merges src into dst.
@@ -58,17 +75,24 @@ func Clone(pb Message) Message {
// Elements of repeated fields will be appended.
// Merge panics if src and dst are not the same type, or if dst is nil.
func Merge(dst, src Message) {
+ if m, ok := dst.(Merger); ok {
+ m.Merge(src)
+ return
+ }
+
in := reflect.ValueOf(src)
out := reflect.ValueOf(dst)
if out.IsNil() {
panic("proto: nil destination")
}
if in.Type() != out.Type() {
- // Explicit test prior to mergeStruct so that mistyped nils will fail
- panic("proto: type mismatch")
+ panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src))
}
if in.IsNil() {
- // Merging nil into non-nil is a quiet no-op
+ return // Merge from nil src is a noop
+ }
+ if m, ok := dst.(generatedMerger); ok {
+ m.XXX_Merge(src)
return
}
mergeStruct(out.Elem(), in.Elem())
@@ -84,7 +108,7 @@ func mergeStruct(out, in reflect.Value) {
mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i])
}
- if emIn, ok := extendable(in.Addr().Interface()); ok {
+ if emIn, err := extendable(in.Addr().Interface()); err == nil {
emOut, _ := extendable(out.Addr().Interface())
mIn, muIn := emIn.extensionsRead()
if mIn != nil {
diff --git a/vendor/github.com/golang/protobuf/proto/decode.go b/vendor/github.com/golang/protobuf/proto/decode.go
index aa207298f..63b0f08be 100644
--- a/vendor/github.com/golang/protobuf/proto/decode.go
+++ b/vendor/github.com/golang/protobuf/proto/decode.go
@@ -39,8 +39,6 @@ import (
"errors"
"fmt"
"io"
- "os"
- "reflect"
)
// errOverflow is returned when an integer is too large to be represented.
@@ -50,10 +48,6 @@ var errOverflow = errors.New("proto: integer overflow")
// wire type is encountered. It does not get returned to user code.
var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")
-// The fundamental decoders that interpret bytes on the wire.
-// Those that take integer types all return uint64 and are
-// therefore of type valueDecoder.
-
// DecodeVarint reads a varint-encoded integer from the slice.
// It returns the integer and the number of bytes consumed, or
// zero if there is not enough.
@@ -192,7 +186,6 @@ func (p *Buffer) DecodeVarint() (x uint64, err error) {
if b&0x80 == 0 {
goto done
}
- // x -= 0x80 << 63 // Always zero.
return 0, errOverflow
@@ -267,9 +260,6 @@ func (p *Buffer) DecodeZigzag32() (x uint64, err error) {
return
}
-// These are not ValueDecoders: they produce an array of bytes or a string.
-// bytes, embedded messages
-
// DecodeRawBytes reads a count-delimited byte buffer from the Buffer.
// This is the format used for the bytes protocol buffer
// type and for embedded messages.
@@ -311,81 +301,29 @@ func (p *Buffer) DecodeStringBytes() (s string, err error) {
return string(buf), nil
}
-// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
-// If the protocol buffer has extensions, and the field matches, add it as an extension.
-// Otherwise, if the XXX_unrecognized field exists, append the skipped data there.
-func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error {
- oi := o.index
-
- err := o.skip(t, tag, wire)
- if err != nil {
- return err
- }
-
- if !unrecField.IsValid() {
- return nil
- }
-
- ptr := structPointer_Bytes(base, unrecField)
-
- // Add the skipped field to struct field
- obuf := o.buf
-
- o.buf = *ptr
- o.EncodeVarint(uint64(tag<<3 | wire))
- *ptr = append(o.buf, obuf[oi:o.index]...)
-
- o.buf = obuf
-
- return nil
-}
-
-// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
-func (o *Buffer) skip(t reflect.Type, tag, wire int) error {
-
- var u uint64
- var err error
-
- switch wire {
- case WireVarint:
- _, err = o.DecodeVarint()
- case WireFixed64:
- _, err = o.DecodeFixed64()
- case WireBytes:
- _, err = o.DecodeRawBytes(false)
- case WireFixed32:
- _, err = o.DecodeFixed32()
- case WireStartGroup:
- for {
- u, err = o.DecodeVarint()
- if err != nil {
- break
- }
- fwire := int(u & 0x7)
- if fwire == WireEndGroup {
- break
- }
- ftag := int(u >> 3)
- err = o.skip(t, ftag, fwire)
- if err != nil {
- break
- }
- }
- default:
- err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t)
- }
- return err
-}
-
// Unmarshaler is the interface representing objects that can
-// unmarshal themselves. The method should reset the receiver before
-// decoding starts. The argument points to data that may be
+// unmarshal themselves. The argument points to data that may be
// overwritten, so implementations should not keep references to the
// buffer.
+// Unmarshal implementations should not clear the receiver.
+// Any unmarshaled data should be merged into the receiver.
+// Callers of Unmarshal that do not want to retain existing data
+// should Reset the receiver before calling Unmarshal.
type Unmarshaler interface {
Unmarshal([]byte) error
}
+// newUnmarshaler is the interface representing objects that can
+// unmarshal themselves. The semantics are identical to Unmarshaler.
+//
+// This exists to support protoc-gen-go generated messages.
+// The proto package will stop type-asserting to this interface in the future.
+//
+// DO NOT DEPEND ON THIS.
+type newUnmarshaler interface {
+ XXX_Unmarshal([]byte) error
+}
+
// Unmarshal parses the protocol buffer representation in buf and places the
// decoded result in pb. If the struct underlying pb does not match
// the data in buf, the results can be unpredictable.
@@ -395,7 +333,13 @@ type Unmarshaler interface {
// to preserve and append to existing data.
func Unmarshal(buf []byte, pb Message) error {
pb.Reset()
- return UnmarshalMerge(buf, pb)
+ if u, ok := pb.(newUnmarshaler); ok {
+ return u.XXX_Unmarshal(buf)
+ }
+ if u, ok := pb.(Unmarshaler); ok {
+ return u.Unmarshal(buf)
+ }
+ return NewBuffer(buf).Unmarshal(pb)
}
// UnmarshalMerge parses the protocol buffer representation in buf and
@@ -405,8 +349,16 @@ func Unmarshal(buf []byte, pb Message) error {
// UnmarshalMerge merges into existing data in pb.
// Most code should use Unmarshal instead.
func UnmarshalMerge(buf []byte, pb Message) error {
- // If the object can unmarshal itself, let it.
+ if u, ok := pb.(newUnmarshaler); ok {
+ return u.XXX_Unmarshal(buf)
+ }
if u, ok := pb.(Unmarshaler); ok {
+ // NOTE: The history of proto have unfortunately been inconsistent
+ // whether Unmarshaler should or should not implicitly clear itself.
+ // Some implementations do, most do not.
+ // Thus, calling this here may or may not do what people want.
+ //
+ // See https://github.com/golang/protobuf/issues/424
return u.Unmarshal(buf)
}
return NewBuffer(buf).Unmarshal(pb)
@@ -422,12 +374,17 @@ func (p *Buffer) DecodeMessage(pb Message) error {
}
// DecodeGroup reads a tag-delimited group from the Buffer.
+// StartGroup tag is already consumed. This function consumes
+// EndGroup tag.
func (p *Buffer) DecodeGroup(pb Message) error {
- typ, base, err := getbase(pb)
- if err != nil {
- return err
+ b := p.buf[p.index:]
+ x, y := findEndGroup(b)
+ if x < 0 {
+ return io.ErrUnexpectedEOF
}
- return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base)
+ err := Unmarshal(b[:x], pb)
+ p.index += y
+ return err
}
// Unmarshal parses the protocol buffer representation in the
@@ -438,533 +395,33 @@ func (p *Buffer) DecodeGroup(pb Message) error {
// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal.
func (p *Buffer) Unmarshal(pb Message) error {
// If the object can unmarshal itself, let it.
- if u, ok := pb.(Unmarshaler); ok {
- err := u.Unmarshal(p.buf[p.index:])
+ if u, ok := pb.(newUnmarshaler); ok {
+ err := u.XXX_Unmarshal(p.buf[p.index:])
p.index = len(p.buf)
return err
}
-
- typ, base, err := getbase(pb)
- if err != nil {
- return err
- }
-
- err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base)
-
- if collectStats {
- stats.Decode++
- }
-
- return err
-}
-
-// unmarshalType does the work of unmarshaling a structure.
-func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error {
- var state errorState
- required, reqFields := prop.reqCount, uint64(0)
-
- var err error
- for err == nil && o.index < len(o.buf) {
- oi := o.index
- var u uint64
- u, err = o.DecodeVarint()
- if err != nil {
- break
- }
- wire := int(u & 0x7)
- if wire == WireEndGroup {
- if is_group {
- if required > 0 {
- // Not enough information to determine the exact field.
- // (See below.)
- return &RequiredNotSetError{"{Unknown}"}
- }
- return nil // input is satisfied
- }
- return fmt.Errorf("proto: %s: wiretype end group for non-group", st)
- }
- tag := int(u >> 3)
- if tag <= 0 {
- return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire)
- }
- fieldnum, ok := prop.decoderTags.get(tag)
- if !ok {
- // Maybe it's an extension?
- if prop.extendable {
- if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) {
- if err = o.skip(st, tag, wire); err == nil {
- extmap := e.extensionsWrite()
- ext := extmap[int32(tag)] // may be missing
- ext.enc = append(ext.enc, o.buf[oi:o.index]...)
- extmap[int32(tag)] = ext
- }
- continue
- }
- }
- // Maybe it's a oneof?
- if prop.oneofUnmarshaler != nil {
- m := structPointer_Interface(base, st).(Message)
- // First return value indicates whether tag is a oneof field.
- ok, err = prop.oneofUnmarshaler(m, tag, wire, o)
- if err == ErrInternalBadWireType {
- // Map the error to something more descriptive.
- // Do the formatting here to save generated code space.
- err = fmt.Errorf("bad wiretype for oneof field in %T", m)
- }
- if ok {
- continue
- }
- }
- err = o.skipAndSave(st, tag, wire, base, prop.unrecField)
- continue
- }
- p := prop.Prop[fieldnum]
-
- if p.dec == nil {
- fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name)
- continue
- }
- dec := p.dec
- if wire != WireStartGroup && wire != p.WireType {
- if wire == WireBytes && p.packedDec != nil {
- // a packable field
- dec = p.packedDec
- } else {
- err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType)
- continue
- }
- }
- decErr := dec(o, p, base)
- if decErr != nil && !state.shouldContinue(decErr, p) {
- err = decErr
- }
- if err == nil && p.Required {
- // Successfully decoded a required field.
- if tag <= 64 {
- // use bitmap for fields 1-64 to catch field reuse.
- var mask uint64 = 1 << uint64(tag-1)
- if reqFields&mask == 0 {
- // new required field
- reqFields |= mask
- required--
- }
- } else {
- // This is imprecise. It can be fooled by a required field
- // with a tag > 64 that is encoded twice; that's very rare.
- // A fully correct implementation would require allocating
- // a data structure, which we would like to avoid.
- required--
- }
- }
- }
- if err == nil {
- if is_group {
- return io.ErrUnexpectedEOF
- }
- if state.err != nil {
- return state.err
- }
- if required > 0 {
- // Not enough information to determine the exact field. If we use extra
- // CPU, we could determine the field only if the missing required field
- // has a tag <= 64 and we check reqFields.
- return &RequiredNotSetError{"{Unknown}"}
- }
- }
- return err
-}
-
-// Individual type decoders
-// For each,
-// u is the decoded value,
-// v is a pointer to the field (pointer) in the struct
-
-// Sizes of the pools to allocate inside the Buffer.
-// The goal is modest amortization and allocation
-// on at least 16-byte boundaries.
-const (
- boolPoolSize = 16
- uint32PoolSize = 8
- uint64PoolSize = 4
-)
-
-// Decode a bool.
-func (o *Buffer) dec_bool(p *Properties, base structPointer) error {
- u, err := p.valDec(o)
- if err != nil {
- return err
- }
- if len(o.bools) == 0 {
- o.bools = make([]bool, boolPoolSize)
- }
- o.bools[0] = u != 0
- *structPointer_Bool(base, p.field) = &o.bools[0]
- o.bools = o.bools[1:]
- return nil
-}
-
-func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error {
- u, err := p.valDec(o)
- if err != nil {
- return err
- }
- *structPointer_BoolVal(base, p.field) = u != 0
- return nil
-}
-
-// Decode an int32.
-func (o *Buffer) dec_int32(p *Properties, base structPointer) error {
- u, err := p.valDec(o)
- if err != nil {
- return err
- }
- word32_Set(structPointer_Word32(base, p.field), o, uint32(u))
- return nil
-}
-
-func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error {
- u, err := p.valDec(o)
- if err != nil {
- return err
- }
- word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u))
- return nil
-}
-
-// Decode an int64.
-func (o *Buffer) dec_int64(p *Properties, base structPointer) error {
- u, err := p.valDec(o)
- if err != nil {
- return err
- }
- word64_Set(structPointer_Word64(base, p.field), o, u)
- return nil
-}
-
-func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error {
- u, err := p.valDec(o)
- if err != nil {
- return err
- }
- word64Val_Set(structPointer_Word64Val(base, p.field), o, u)
- return nil
-}
-
-// Decode a string.
-func (o *Buffer) dec_string(p *Properties, base structPointer) error {
- s, err := o.DecodeStringBytes()
- if err != nil {
- return err
- }
- *structPointer_String(base, p.field) = &s
- return nil
-}
-
-func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error {
- s, err := o.DecodeStringBytes()
- if err != nil {
- return err
- }
- *structPointer_StringVal(base, p.field) = s
- return nil
-}
-
-// Decode a slice of bytes ([]byte).
-func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error {
- b, err := o.DecodeRawBytes(true)
- if err != nil {
- return err
- }
- *structPointer_Bytes(base, p.field) = b
- return nil
-}
-
-// Decode a slice of bools ([]bool).
-func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error {
- u, err := p.valDec(o)
- if err != nil {
- return err
- }
- v := structPointer_BoolSlice(base, p.field)
- *v = append(*v, u != 0)
- return nil
-}
-
-// Decode a slice of bools ([]bool) in packed format.
-func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error {
- v := structPointer_BoolSlice(base, p.field)
-
- nn, err := o.DecodeVarint()
- if err != nil {
- return err
- }
- nb := int(nn) // number of bytes of encoded bools
- fin := o.index + nb
- if fin < o.index {
- return errOverflow
- }
-
- y := *v
- for o.index < fin {
- u, err := p.valDec(o)
- if err != nil {
- return err
- }
- y = append(y, u != 0)
- }
-
- *v = y
- return nil
-}
-
-// Decode a slice of int32s ([]int32).
-func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error {
- u, err := p.valDec(o)
- if err != nil {
- return err
- }
- structPointer_Word32Slice(base, p.field).Append(uint32(u))
- return nil
-}
-
-// Decode a slice of int32s ([]int32) in packed format.
-func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error {
- v := structPointer_Word32Slice(base, p.field)
-
- nn, err := o.DecodeVarint()
- if err != nil {
- return err
- }
- nb := int(nn) // number of bytes of encoded int32s
-
- fin := o.index + nb
- if fin < o.index {
- return errOverflow
- }
- for o.index < fin {
- u, err := p.valDec(o)
- if err != nil {
- return err
- }
- v.Append(uint32(u))
- }
- return nil
-}
-
-// Decode a slice of int64s ([]int64).
-func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error {
- u, err := p.valDec(o)
- if err != nil {
- return err
- }
-
- structPointer_Word64Slice(base, p.field).Append(u)
- return nil
-}
-
-// Decode a slice of int64s ([]int64) in packed format.
-func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error {
- v := structPointer_Word64Slice(base, p.field)
-
- nn, err := o.DecodeVarint()
- if err != nil {
- return err
- }
- nb := int(nn) // number of bytes of encoded int64s
-
- fin := o.index + nb
- if fin < o.index {
- return errOverflow
- }
- for o.index < fin {
- u, err := p.valDec(o)
- if err != nil {
- return err
- }
- v.Append(u)
- }
- return nil
-}
-
-// Decode a slice of strings ([]string).
-func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error {
- s, err := o.DecodeStringBytes()
- if err != nil {
- return err
- }
- v := structPointer_StringSlice(base, p.field)
- *v = append(*v, s)
- return nil
-}
-
-// Decode a slice of slice of bytes ([][]byte).
-func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error {
- b, err := o.DecodeRawBytes(true)
- if err != nil {
- return err
- }
- v := structPointer_BytesSlice(base, p.field)
- *v = append(*v, b)
- return nil
-}
-
-// Decode a map field.
-func (o *Buffer) dec_new_map(p *Properties, base structPointer) error {
- raw, err := o.DecodeRawBytes(false)
- if err != nil {
- return err
- }
- oi := o.index // index at the end of this map entry
- o.index -= len(raw) // move buffer back to start of map entry
-
- mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V
- if mptr.Elem().IsNil() {
- mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem()))
- }
- v := mptr.Elem() // map[K]V
-
- // Prepare addressable doubly-indirect placeholders for the key and value types.
- // See enc_new_map for why.
- keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K
- keybase := toStructPointer(keyptr.Addr()) // **K
-
- var valbase structPointer
- var valptr reflect.Value
- switch p.mtype.Elem().Kind() {
- case reflect.Slice:
- // []byte
- var dummy []byte
- valptr = reflect.ValueOf(&dummy) // *[]byte
- valbase = toStructPointer(valptr) // *[]byte
- case reflect.Ptr:
- // message; valptr is **Msg; need to allocate the intermediate pointer
- valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V
- valptr.Set(reflect.New(valptr.Type().Elem()))
- valbase = toStructPointer(valptr)
- default:
- // everything else
- valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V
- valbase = toStructPointer(valptr.Addr()) // **V
- }
-
- // Decode.
- // This parses a restricted wire format, namely the encoding of a message
- // with two fields. See enc_new_map for the format.
- for o.index < oi {
- // tagcode for key and value properties are always a single byte
- // because they have tags 1 and 2.
- tagcode := o.buf[o.index]
- o.index++
- switch tagcode {
- case p.mkeyprop.tagcode[0]:
- if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil {
- return err
- }
- case p.mvalprop.tagcode[0]:
- if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil {
- return err
- }
- default:
- // TODO: Should we silently skip this instead?
- return fmt.Errorf("proto: bad map data tag %d", raw[0])
- }
- }
- keyelem, valelem := keyptr.Elem(), valptr.Elem()
- if !keyelem.IsValid() {
- keyelem = reflect.Zero(p.mtype.Key())
- }
- if !valelem.IsValid() {
- valelem = reflect.Zero(p.mtype.Elem())
- }
-
- v.SetMapIndex(keyelem, valelem)
- return nil
-}
-
-// Decode a group.
-func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error {
- bas := structPointer_GetStructPointer(base, p.field)
- if structPointer_IsNil(bas) {
- // allocate new nested message
- bas = toStructPointer(reflect.New(p.stype))
- structPointer_SetStructPointer(base, p.field, bas)
- }
- return o.unmarshalType(p.stype, p.sprop, true, bas)
-}
-
-// Decode an embedded message.
-func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) {
- raw, e := o.DecodeRawBytes(false)
- if e != nil {
- return e
- }
-
- bas := structPointer_GetStructPointer(base, p.field)
- if structPointer_IsNil(bas) {
- // allocate new nested message
- bas = toStructPointer(reflect.New(p.stype))
- structPointer_SetStructPointer(base, p.field, bas)
- }
-
- // If the object can unmarshal itself, let it.
- if p.isUnmarshaler {
- iv := structPointer_Interface(bas, p.stype)
- return iv.(Unmarshaler).Unmarshal(raw)
- }
-
- obuf := o.buf
- oi := o.index
- o.buf = raw
- o.index = 0
-
- err = o.unmarshalType(p.stype, p.sprop, false, bas)
- o.buf = obuf
- o.index = oi
-
- return err
-}
-
-// Decode a slice of embedded messages.
-func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error {
- return o.dec_slice_struct(p, false, base)
-}
-
-// Decode a slice of embedded groups.
-func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error {
- return o.dec_slice_struct(p, true, base)
-}
-
-// Decode a slice of structs ([]*struct).
-func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error {
- v := reflect.New(p.stype)
- bas := toStructPointer(v)
- structPointer_StructPointerSlice(base, p.field).Append(bas)
-
- if is_group {
- err := o.unmarshalType(p.stype, p.sprop, is_group, bas)
- return err
- }
-
- raw, err := o.DecodeRawBytes(false)
- if err != nil {
+ if u, ok := pb.(Unmarshaler); ok {
+ // NOTE: The history of proto have unfortunately been inconsistent
+ // whether Unmarshaler should or should not implicitly clear itself.
+ // Some implementations do, most do not.
+ // Thus, calling this here may or may not do what people want.
+ //
+ // See https://github.com/golang/protobuf/issues/424
+ err := u.Unmarshal(p.buf[p.index:])
+ p.index = len(p.buf)
return err
}
- // If the object can unmarshal itself, let it.
- if p.isUnmarshaler {
- iv := v.Interface()
- return iv.(Unmarshaler).Unmarshal(raw)
- }
-
- obuf := o.buf
- oi := o.index
- o.buf = raw
- o.index = 0
-
- err = o.unmarshalType(p.stype, p.sprop, is_group, bas)
-
- o.buf = obuf
- o.index = oi
-
+ // Slow workaround for messages that aren't Unmarshalers.
+ // This includes some hand-coded .pb.go files and
+ // bootstrap protos.
+ // TODO: fix all of those and then add Unmarshal to
+ // the Message interface. Then:
+ // The cast above and code below can be deleted.
+ // The old unmarshaler can be deleted.
+ // Clients can call Unmarshal directly (can already do that, actually).
+ var info InternalMessageInfo
+ err := info.Unmarshal(pb, p.buf[p.index:])
+ p.index = len(p.buf)
return err
}
diff --git a/vendor/github.com/golang/protobuf/proto/deprecated.go b/vendor/github.com/golang/protobuf/proto/deprecated.go
new file mode 100644
index 000000000..35b882c09
--- /dev/null
+++ b/vendor/github.com/golang/protobuf/proto/deprecated.go
@@ -0,0 +1,63 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2018 The Go Authors. All rights reserved.
+// https://github.com/golang/protobuf
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto
+
+import "errors"
+
+// Deprecated: do not use.
+type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 }
+
+// Deprecated: do not use.
+func GetStats() Stats { return Stats{} }
+
+// Deprecated: do not use.
+func MarshalMessageSet(interface{}) ([]byte, error) {
+ return nil, errors.New("proto: not implemented")
+}
+
+// Deprecated: do not use.
+func UnmarshalMessageSet([]byte, interface{}) error {
+ return errors.New("proto: not implemented")
+}
+
+// Deprecated: do not use.
+func MarshalMessageSetJSON(interface{}) ([]byte, error) {
+ return nil, errors.New("proto: not implemented")
+}
+
+// Deprecated: do not use.
+func UnmarshalMessageSetJSON([]byte, interface{}) error {
+ return errors.New("proto: not implemented")
+}
+
+// Deprecated: do not use.
+func RegisterMessageSetType(Message, int32, string) {}
diff --git a/vendor/github.com/golang/protobuf/proto/discard.go b/vendor/github.com/golang/protobuf/proto/discard.go
new file mode 100644
index 000000000..dea2617ce
--- /dev/null
+++ b/vendor/github.com/golang/protobuf/proto/discard.go
@@ -0,0 +1,350 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2017 The Go Authors. All rights reserved.
+// https://github.com/golang/protobuf
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+ "sync"
+ "sync/atomic"
+)
+
+type generatedDiscarder interface {
+ XXX_DiscardUnknown()
+}
+
+// DiscardUnknown recursively discards all unknown fields from this message
+// and all embedded messages.
+//
+// When unmarshaling a message with unrecognized fields, the tags and values
+// of such fields are preserved in the Message. This allows a later call to
+// marshal to be able to produce a message that continues to have those
+// unrecognized fields. To avoid this, DiscardUnknown is used to
+// explicitly clear the unknown fields after unmarshaling.
+//
+// For proto2 messages, the unknown fields of message extensions are only
+// discarded from messages that have been accessed via GetExtension.
+func DiscardUnknown(m Message) {
+ if m, ok := m.(generatedDiscarder); ok {
+ m.XXX_DiscardUnknown()
+ return
+ }
+ // TODO: Dynamically populate a InternalMessageInfo for legacy messages,
+ // but the master branch has no implementation for InternalMessageInfo,
+ // so it would be more work to replicate that approach.
+ discardLegacy(m)
+}
+
+// DiscardUnknown recursively discards all unknown fields.
+func (a *InternalMessageInfo) DiscardUnknown(m Message) {
+ di := atomicLoadDiscardInfo(&a.discard)
+ if di == nil {
+ di = getDiscardInfo(reflect.TypeOf(m).Elem())
+ atomicStoreDiscardInfo(&a.discard, di)
+ }
+ di.discard(toPointer(&m))
+}
+
+type discardInfo struct {
+ typ reflect.Type
+
+ initialized int32 // 0: only typ is valid, 1: everything is valid
+ lock sync.Mutex
+
+ fields []discardFieldInfo
+ unrecognized field
+}
+
+type discardFieldInfo struct {
+ field field // Offset of field, guaranteed to be valid
+ discard func(src pointer)
+}
+
+var (
+ discardInfoMap = map[reflect.Type]*discardInfo{}
+ discardInfoLock sync.Mutex
+)
+
+func getDiscardInfo(t reflect.Type) *discardInfo {
+ discardInfoLock.Lock()
+ defer discardInfoLock.Unlock()
+ di := discardInfoMap[t]
+ if di == nil {
+ di = &discardInfo{typ: t}
+ discardInfoMap[t] = di
+ }
+ return di
+}
+
+func (di *discardInfo) discard(src pointer) {
+ if src.isNil() {
+ return // Nothing to do.
+ }
+
+ if atomic.LoadInt32(&di.initialized) == 0 {
+ di.computeDiscardInfo()
+ }
+
+ for _, fi := range di.fields {
+ sfp := src.offset(fi.field)
+ fi.discard(sfp)
+ }
+
+ // For proto2 messages, only discard unknown fields in message extensions
+ // that have been accessed via GetExtension.
+ if em, err := extendable(src.asPointerTo(di.typ).Interface()); err == nil {
+ // Ignore lock since DiscardUnknown is not concurrency safe.
+ emm, _ := em.extensionsRead()
+ for _, mx := range emm {
+ if m, ok := mx.value.(Message); ok {
+ DiscardUnknown(m)
+ }
+ }
+ }
+
+ if di.unrecognized.IsValid() {
+ *src.offset(di.unrecognized).toBytes() = nil
+ }
+}
+
+func (di *discardInfo) computeDiscardInfo() {
+ di.lock.Lock()
+ defer di.lock.Unlock()
+ if di.initialized != 0 {
+ return
+ }
+ t := di.typ
+ n := t.NumField()
+
+ for i := 0; i < n; i++ {
+ f := t.Field(i)
+ if strings.HasPrefix(f.Name, "XXX_") {
+ continue
+ }
+
+ dfi := discardFieldInfo{field: toField(&f)}
+ tf := f.Type
+
+ // Unwrap tf to get its most basic type.
+ var isPointer, isSlice bool
+ if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
+ isSlice = true
+ tf = tf.Elem()
+ }
+ if tf.Kind() == reflect.Ptr {
+ isPointer = true
+ tf = tf.Elem()
+ }
+ if isPointer && isSlice && tf.Kind() != reflect.Struct {
+ panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", t, f.Name))
+ }
+
+ switch tf.Kind() {
+ case reflect.Struct:
+ switch {
+ case !isPointer:
+ panic(fmt.Sprintf("%v.%s cannot be a direct struct value", t, f.Name))
+ case isSlice: // E.g., []*pb.T
+ di := getDiscardInfo(tf)
+ dfi.discard = func(src pointer) {
+ sps := src.getPointerSlice()
+ for _, sp := range sps {
+ if !sp.isNil() {
+ di.discard(sp)
+ }
+ }
+ }
+ default: // E.g., *pb.T
+ di := getDiscardInfo(tf)
+ dfi.discard = func(src pointer) {
+ sp := src.getPointer()
+ if !sp.isNil() {
+ di.discard(sp)
+ }
+ }
+ }
+ case reflect.Map:
+ switch {
+ case isPointer || isSlice:
+ panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", t, f.Name))
+ default: // E.g., map[K]V
+ if tf.Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T)
+ dfi.discard = func(src pointer) {
+ sm := src.asPointerTo(tf).Elem()
+ if sm.Len() == 0 {
+ return
+ }
+ for _, key := range sm.MapKeys() {
+ val := sm.MapIndex(key)
+ DiscardUnknown(val.Interface().(Message))
+ }
+ }
+ } else {
+ dfi.discard = func(pointer) {} // Noop
+ }
+ }
+ case reflect.Interface:
+ // Must be oneof field.
+ switch {
+ case isPointer || isSlice:
+ panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", t, f.Name))
+ default: // E.g., interface{}
+ // TODO: Make this faster?
+ dfi.discard = func(src pointer) {
+ su := src.asPointerTo(tf).Elem()
+ if !su.IsNil() {
+ sv := su.Elem().Elem().Field(0)
+ if sv.Kind() == reflect.Ptr && sv.IsNil() {
+ return
+ }
+ switch sv.Type().Kind() {
+ case reflect.Ptr: // Proto struct (e.g., *T)
+ DiscardUnknown(sv.Interface().(Message))
+ }
+ }
+ }
+ }
+ default:
+ continue
+ }
+ di.fields = append(di.fields, dfi)
+ }
+
+ di.unrecognized = invalidField
+ if f, ok := t.FieldByName("XXX_unrecognized"); ok {
+ if f.Type != reflect.TypeOf([]byte{}) {
+ panic("expected XXX_unrecognized to be of type []byte")
+ }
+ di.unrecognized = toField(&f)
+ }
+
+ atomic.StoreInt32(&di.initialized, 1)
+}
+
+func discardLegacy(m Message) {
+ v := reflect.ValueOf(m)
+ if v.Kind() != reflect.Ptr || v.IsNil() {
+ return
+ }
+ v = v.Elem()
+ if v.Kind() != reflect.Struct {
+ return
+ }
+ t := v.Type()
+
+ for i := 0; i < v.NumField(); i++ {
+ f := t.Field(i)
+ if strings.HasPrefix(f.Name, "XXX_") {
+ continue
+ }
+ vf := v.Field(i)
+ tf := f.Type
+
+ // Unwrap tf to get its most basic type.
+ var isPointer, isSlice bool
+ if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
+ isSlice = true
+ tf = tf.Elem()
+ }
+ if tf.Kind() == reflect.Ptr {
+ isPointer = true
+ tf = tf.Elem()
+ }
+ if isPointer && isSlice && tf.Kind() != reflect.Struct {
+ panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name))
+ }
+
+ switch tf.Kind() {
+ case reflect.Struct:
+ switch {
+ case !isPointer:
+ panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name))
+ case isSlice: // E.g., []*pb.T
+ for j := 0; j < vf.Len(); j++ {
+ discardLegacy(vf.Index(j).Interface().(Message))
+ }
+ default: // E.g., *pb.T
+ discardLegacy(vf.Interface().(Message))
+ }
+ case reflect.Map:
+ switch {
+ case isPointer || isSlice:
+ panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name))
+ default: // E.g., map[K]V
+ tv := vf.Type().Elem()
+ if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T)
+ for _, key := range vf.MapKeys() {
+ val := vf.MapIndex(key)
+ discardLegacy(val.Interface().(Message))
+ }
+ }
+ }
+ case reflect.Interface:
+ // Must be oneof field.
+ switch {
+ case isPointer || isSlice:
+ panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name))
+ default: // E.g., test_proto.isCommunique_Union interface
+ if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" {
+ vf = vf.Elem() // E.g., *test_proto.Communique_Msg
+ if !vf.IsNil() {
+ vf = vf.Elem() // E.g., test_proto.Communique_Msg
+ vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value
+ if vf.Kind() == reflect.Ptr {
+ discardLegacy(vf.Interface().(Message))
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() {
+ if vf.Type() != reflect.TypeOf([]byte{}) {
+ panic("expected XXX_unrecognized to be of type []byte")
+ }
+ vf.Set(reflect.ValueOf([]byte(nil)))
+ }
+
+ // For proto2 messages, only discard unknown fields in message extensions
+ // that have been accessed via GetExtension.
+ if em, err := extendable(m); err == nil {
+ // Ignore lock since discardLegacy is not concurrency safe.
+ emm, _ := em.extensionsRead()
+ for _, mx := range emm {
+ if m, ok := mx.value.(Message); ok {
+ discardLegacy(m)
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/golang/protobuf/proto/encode.go b/vendor/github.com/golang/protobuf/proto/encode.go
index 8b84d1b22..3abfed2cf 100644
--- a/vendor/github.com/golang/protobuf/proto/encode.go
+++ b/vendor/github.com/golang/protobuf/proto/encode.go
@@ -37,28 +37,9 @@ package proto
import (
"errors"
- "fmt"
"reflect"
- "sort"
)
-// RequiredNotSetError is the error returned if Marshal is called with
-// a protocol buffer struct whose required fields have not
-// all been initialized. It is also the error returned if Unmarshal is
-// called with an encoded protocol buffer that does not include all the
-// required fields.
-//
-// When printed, RequiredNotSetError reports the first unset required field in a
-// message. If the field cannot be precisely determined, it is reported as
-// "{Unknown}".
-type RequiredNotSetError struct {
- field string
-}
-
-func (e *RequiredNotSetError) Error() string {
- return fmt.Sprintf("proto: required field %q not set", e.field)
-}
-
var (
// errRepeatedHasNil is the error returned if Marshal is called with
// a struct with a repeated field containing a nil element.
@@ -82,10 +63,6 @@ var (
const maxVarintBytes = 10 // maximum length of a varint
-// maxMarshalSize is the largest allowed size of an encoded protobuf,
-// since C++ and Java use signed int32s for the size.
-const maxMarshalSize = 1<<31 - 1
-
// EncodeVarint returns the varint encoding of x.
// This is the format for the
// int32, int64, uint32, uint64, bool, and enum
@@ -119,18 +96,27 @@ func (p *Buffer) EncodeVarint(x uint64) error {
// SizeVarint returns the varint encoding size of an integer.
func SizeVarint(x uint64) int {
- return sizeVarint(x)
-}
-
-func sizeVarint(x uint64) (n int) {
- for {
- n++
- x >>= 7
- if x == 0 {
- break
- }
- }
- return n
+ switch {
+ case x < 1<<7:
+ return 1
+ case x < 1<<14:
+ return 2
+ case x < 1<<21:
+ return 3
+ case x < 1<<28:
+ return 4
+ case x < 1<<35:
+ return 5
+ case x < 1<<42:
+ return 6
+ case x < 1<<49:
+ return 7
+ case x < 1<<56:
+ return 8
+ case x < 1<<63:
+ return 9
+ }
+ return 10
}
// EncodeFixed64 writes a 64-bit integer to the Buffer.
@@ -149,10 +135,6 @@ func (p *Buffer) EncodeFixed64(x uint64) error {
return nil
}
-func sizeFixed64(x uint64) int {
- return 8
-}
-
// EncodeFixed32 writes a 32-bit integer to the Buffer.
// This is the format for the
// fixed32, sfixed32, and float protocol buffer types.
@@ -165,20 +147,12 @@ func (p *Buffer) EncodeFixed32(x uint64) error {
return nil
}
-func sizeFixed32(x uint64) int {
- return 4
-}
-
// EncodeZigzag64 writes a zigzag-encoded 64-bit integer
// to the Buffer.
// This is the format used for the sint64 protocol buffer type.
func (p *Buffer) EncodeZigzag64(x uint64) error {
// use signed number to get arithmetic right shift.
- return p.EncodeVarint((x << 1) ^ uint64((int64(x) >> 63)))
-}
-
-func sizeZigzag64(x uint64) int {
- return sizeVarint((x << 1) ^ uint64((int64(x) >> 63)))
+ return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
// EncodeZigzag32 writes a zigzag-encoded 32-bit integer
@@ -189,10 +163,6 @@ func (p *Buffer) EncodeZigzag32(x uint64) error {
return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31))))
}
-func sizeZigzag32(x uint64) int {
- return sizeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31))))
-}
-
// EncodeRawBytes writes a count-delimited byte buffer to the Buffer.
// This is the format used for the bytes protocol buffer
// type and for embedded messages.
@@ -202,11 +172,6 @@ func (p *Buffer) EncodeRawBytes(b []byte) error {
return nil
}
-func sizeRawBytes(b []byte) int {
- return sizeVarint(uint64(len(b))) +
- len(b)
-}
-
// EncodeStringBytes writes an encoded string to the Buffer.
// This is the format used for the proto2 string type.
func (p *Buffer) EncodeStringBytes(s string) error {
@@ -215,319 +180,17 @@ func (p *Buffer) EncodeStringBytes(s string) error {
return nil
}
-func sizeStringBytes(s string) int {
- return sizeVarint(uint64(len(s))) +
- len(s)
-}
-
// Marshaler is the interface representing objects that can marshal themselves.
type Marshaler interface {
Marshal() ([]byte, error)
}
-// Marshal takes the protocol buffer
-// and encodes it into the wire format, returning the data.
-func Marshal(pb Message) ([]byte, error) {
- // Can the object marshal itself?
- if m, ok := pb.(Marshaler); ok {
- return m.Marshal()
- }
- p := NewBuffer(nil)
- err := p.Marshal(pb)
- if p.buf == nil && err == nil {
- // Return a non-nil slice on success.
- return []byte{}, nil
- }
- return p.buf, err
-}
-
// EncodeMessage writes the protocol buffer to the Buffer,
// prefixed by a varint-encoded length.
func (p *Buffer) EncodeMessage(pb Message) error {
- t, base, err := getbase(pb)
- if structPointer_IsNil(base) {
- return ErrNil
- }
- if err == nil {
- var state errorState
- err = p.enc_len_struct(GetProperties(t.Elem()), base, &state)
- }
- return err
-}
-
-// Marshal takes the protocol buffer
-// and encodes it into the wire format, writing the result to the
-// Buffer.
-func (p *Buffer) Marshal(pb Message) error {
- // Can the object marshal itself?
- if m, ok := pb.(Marshaler); ok {
- data, err := m.Marshal()
- p.buf = append(p.buf, data...)
- return err
- }
-
- t, base, err := getbase(pb)
- if structPointer_IsNil(base) {
- return ErrNil
- }
- if err == nil {
- err = p.enc_struct(GetProperties(t.Elem()), base)
- }
-
- if collectStats {
- (stats).Encode++ // Parens are to work around a goimports bug.
- }
-
- if len(p.buf) > maxMarshalSize {
- return ErrTooLarge
- }
- return err
-}
-
-// Size returns the encoded size of a protocol buffer.
-func Size(pb Message) (n int) {
- // Can the object marshal itself? If so, Size is slow.
- // TODO: add Size to Marshaler, or add a Sizer interface.
- if m, ok := pb.(Marshaler); ok {
- b, _ := m.Marshal()
- return len(b)
- }
-
- t, base, err := getbase(pb)
- if structPointer_IsNil(base) {
- return 0
- }
- if err == nil {
- n = size_struct(GetProperties(t.Elem()), base)
- }
-
- if collectStats {
- (stats).Size++ // Parens are to work around a goimports bug.
- }
-
- return
-}
-
-// Individual type encoders.
-
-// Encode a bool.
-func (o *Buffer) enc_bool(p *Properties, base structPointer) error {
- v := *structPointer_Bool(base, p.field)
- if v == nil {
- return ErrNil
- }
- x := 0
- if *v {
- x = 1
- }
- o.buf = append(o.buf, p.tagcode...)
- p.valEnc(o, uint64(x))
- return nil
-}
-
-func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error {
- v := *structPointer_BoolVal(base, p.field)
- if !v {
- return ErrNil
- }
- o.buf = append(o.buf, p.tagcode...)
- p.valEnc(o, 1)
- return nil
-}
-
-func size_bool(p *Properties, base structPointer) int {
- v := *structPointer_Bool(base, p.field)
- if v == nil {
- return 0
- }
- return len(p.tagcode) + 1 // each bool takes exactly one byte
-}
-
-func size_proto3_bool(p *Properties, base structPointer) int {
- v := *structPointer_BoolVal(base, p.field)
- if !v && !p.oneof {
- return 0
- }
- return len(p.tagcode) + 1 // each bool takes exactly one byte
-}
-
-// Encode an int32.
-func (o *Buffer) enc_int32(p *Properties, base structPointer) error {
- v := structPointer_Word32(base, p.field)
- if word32_IsNil(v) {
- return ErrNil
- }
- x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range
- o.buf = append(o.buf, p.tagcode...)
- p.valEnc(o, uint64(x))
- return nil
-}
-
-func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error {
- v := structPointer_Word32Val(base, p.field)
- x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range
- if x == 0 {
- return ErrNil
- }
- o.buf = append(o.buf, p.tagcode...)
- p.valEnc(o, uint64(x))
- return nil
-}
-
-func size_int32(p *Properties, base structPointer) (n int) {
- v := structPointer_Word32(base, p.field)
- if word32_IsNil(v) {
- return 0
- }
- x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range
- n += len(p.tagcode)
- n += p.valSize(uint64(x))
- return
-}
-
-func size_proto3_int32(p *Properties, base structPointer) (n int) {
- v := structPointer_Word32Val(base, p.field)
- x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range
- if x == 0 && !p.oneof {
- return 0
- }
- n += len(p.tagcode)
- n += p.valSize(uint64(x))
- return
-}
-
-// Encode a uint32.
-// Exactly the same as int32, except for no sign extension.
-func (o *Buffer) enc_uint32(p *Properties, base structPointer) error {
- v := structPointer_Word32(base, p.field)
- if word32_IsNil(v) {
- return ErrNil
- }
- x := word32_Get(v)
- o.buf = append(o.buf, p.tagcode...)
- p.valEnc(o, uint64(x))
- return nil
-}
-
-func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error {
- v := structPointer_Word32Val(base, p.field)
- x := word32Val_Get(v)
- if x == 0 {
- return ErrNil
- }
- o.buf = append(o.buf, p.tagcode...)
- p.valEnc(o, uint64(x))
- return nil
-}
-
-func size_uint32(p *Properties, base structPointer) (n int) {
- v := structPointer_Word32(base, p.field)
- if word32_IsNil(v) {
- return 0
- }
- x := word32_Get(v)
- n += len(p.tagcode)
- n += p.valSize(uint64(x))
- return
-}
-
-func size_proto3_uint32(p *Properties, base structPointer) (n int) {
- v := structPointer_Word32Val(base, p.field)
- x := word32Val_Get(v)
- if x == 0 && !p.oneof {
- return 0
- }
- n += len(p.tagcode)
- n += p.valSize(uint64(x))
- return
-}
-
-// Encode an int64.
-func (o *Buffer) enc_int64(p *Properties, base structPointer) error {
- v := structPointer_Word64(base, p.field)
- if word64_IsNil(v) {
- return ErrNil
- }
- x := word64_Get(v)
- o.buf = append(o.buf, p.tagcode...)
- p.valEnc(o, x)
- return nil
-}
-
-func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error {
- v := structPointer_Word64Val(base, p.field)
- x := word64Val_Get(v)
- if x == 0 {
- return ErrNil
- }
- o.buf = append(o.buf, p.tagcode...)
- p.valEnc(o, x)
- return nil
-}
-
-func size_int64(p *Properties, base structPointer) (n int) {
- v := structPointer_Word64(base, p.field)
- if word64_IsNil(v) {
- return 0
- }
- x := word64_Get(v)
- n += len(p.tagcode)
- n += p.valSize(x)
- return
-}
-
-func size_proto3_int64(p *Properties, base structPointer) (n int) {
- v := structPointer_Word64Val(base, p.field)
- x := word64Val_Get(v)
- if x == 0 && !p.oneof {
- return 0
- }
- n += len(p.tagcode)
- n += p.valSize(x)
- return
-}
-
-// Encode a string.
-func (o *Buffer) enc_string(p *Properties, base structPointer) error {
- v := *structPointer_String(base, p.field)
- if v == nil {
- return ErrNil
- }
- x := *v
- o.buf = append(o.buf, p.tagcode...)
- o.EncodeStringBytes(x)
- return nil
-}
-
-func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error {
- v := *structPointer_StringVal(base, p.field)
- if v == "" {
- return ErrNil
- }
- o.buf = append(o.buf, p.tagcode...)
- o.EncodeStringBytes(v)
- return nil
-}
-
-func size_string(p *Properties, base structPointer) (n int) {
- v := *structPointer_String(base, p.field)
- if v == nil {
- return 0
- }
- x := *v
- n += len(p.tagcode)
- n += sizeStringBytes(x)
- return
-}
-
-func size_proto3_string(p *Properties, base structPointer) (n int) {
- v := *structPointer_StringVal(base, p.field)
- if v == "" && !p.oneof {
- return 0
- }
- n += len(p.tagcode)
- n += sizeStringBytes(v)
- return
+ siz := Size(pb)
+ p.EncodeVarint(uint64(siz))
+ return p.Marshal(pb)
}
// All protocol buffer fields are nillable, but be careful.
@@ -538,825 +201,3 @@ func isNil(v reflect.Value) bool {
}
return false
}
-
-// Encode a message struct.
-func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error {
- var state errorState
- structp := structPointer_GetStructPointer(base, p.field)
- if structPointer_IsNil(structp) {
- return ErrNil
- }
-
- // Can the object marshal itself?
- if p.isMarshaler {
- m := structPointer_Interface(structp, p.stype).(Marshaler)
- data, err := m.Marshal()
- if err != nil && !state.shouldContinue(err, nil) {
- return err
- }
- o.buf = append(o.buf, p.tagcode...)
- o.EncodeRawBytes(data)
- return state.err
- }
-
- o.buf = append(o.buf, p.tagcode...)
- return o.enc_len_struct(p.sprop, structp, &state)
-}
-
-func size_struct_message(p *Properties, base structPointer) int {
- structp := structPointer_GetStructPointer(base, p.field)
- if structPointer_IsNil(structp) {
- return 0
- }
-
- // Can the object marshal itself?
- if p.isMarshaler {
- m := structPointer_Interface(structp, p.stype).(Marshaler)
- data, _ := m.Marshal()
- n0 := len(p.tagcode)
- n1 := sizeRawBytes(data)
- return n0 + n1
- }
-
- n0 := len(p.tagcode)
- n1 := size_struct(p.sprop, structp)
- n2 := sizeVarint(uint64(n1)) // size of encoded length
- return n0 + n1 + n2
-}
-
-// Encode a group struct.
-func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error {
- var state errorState
- b := structPointer_GetStructPointer(base, p.field)
- if structPointer_IsNil(b) {
- return ErrNil
- }
-
- o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
- err := o.enc_struct(p.sprop, b)
- if err != nil && !state.shouldContinue(err, nil) {
- return err
- }
- o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
- return state.err
-}
-
-func size_struct_group(p *Properties, base structPointer) (n int) {
- b := structPointer_GetStructPointer(base, p.field)
- if structPointer_IsNil(b) {
- return 0
- }
-
- n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup))
- n += size_struct(p.sprop, b)
- n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup))
- return
-}
-
-// Encode a slice of bools ([]bool).
-func (o *Buffer) enc_slice_bool(p *Properties, base structPointer) error {
- s := *structPointer_BoolSlice(base, p.field)
- l := len(s)
- if l == 0 {
- return ErrNil
- }
- for _, x := range s {
- o.buf = append(o.buf, p.tagcode...)
- v := uint64(0)
- if x {
- v = 1
- }
- p.valEnc(o, v)
- }
- return nil
-}
-
-func size_slice_bool(p *Properties, base structPointer) int {
- s := *structPointer_BoolSlice(base, p.field)
- l := len(s)
- if l == 0 {
- return 0
- }
- return l * (len(p.tagcode) + 1) // each bool takes exactly one byte
-}
-
-// Encode a slice of bools ([]bool) in packed format.
-func (o *Buffer) enc_slice_packed_bool(p *Properties, base structPointer) error {
- s := *structPointer_BoolSlice(base, p.field)
- l := len(s)
- if l == 0 {
- return ErrNil
- }
- o.buf = append(o.buf, p.tagcode...)
- o.EncodeVarint(uint64(l)) // each bool takes exactly one byte
- for _, x := range s {
- v := uint64(0)
- if x {
- v = 1
- }
- p.valEnc(o, v)
- }
- return nil
-}
-
-func size_slice_packed_bool(p *Properties, base structPointer) (n int) {
- s := *structPointer_BoolSlice(base, p.field)
- l := len(s)
- if l == 0 {
- return 0
- }
- n += len(p.tagcode)
- n += sizeVarint(uint64(l))
- n += l // each bool takes exactly one byte
- return
-}
-
-// Encode a slice of bytes ([]byte).
-func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error {
- s := *structPointer_Bytes(base, p.field)
- if s == nil {
- return ErrNil
- }
- o.buf = append(o.buf, p.tagcode...)
- o.EncodeRawBytes(s)
- return nil
-}
-
-func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error {
- s := *structPointer_Bytes(base, p.field)
- if len(s) == 0 {
- return ErrNil
- }
- o.buf = append(o.buf, p.tagcode...)
- o.EncodeRawBytes(s)
- return nil
-}
-
-func size_slice_byte(p *Properties, base structPointer) (n int) {
- s := *structPointer_Bytes(base, p.field)
- if s == nil && !p.oneof {
- return 0
- }
- n += len(p.tagcode)
- n += sizeRawBytes(s)
- return
-}
-
-func size_proto3_slice_byte(p *Properties, base structPointer) (n int) {
- s := *structPointer_Bytes(base, p.field)
- if len(s) == 0 && !p.oneof {
- return 0
- }
- n += len(p.tagcode)
- n += sizeRawBytes(s)
- return
-}
-
-// Encode a slice of int32s ([]int32).
-func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error {
- s := structPointer_Word32Slice(base, p.field)
- l := s.Len()
- if l == 0 {
- return ErrNil
- }
- for i := 0; i < l; i++ {
- o.buf = append(o.buf, p.tagcode...)
- x := int32(s.Index(i)) // permit sign extension to use full 64-bit range
- p.valEnc(o, uint64(x))
- }
- return nil
-}
-
-func size_slice_int32(p *Properties, base structPointer) (n int) {
- s := structPointer_Word32Slice(base, p.field)
- l := s.Len()
- if l == 0 {
- return 0
- }
- for i := 0; i < l; i++ {
- n += len(p.tagcode)
- x := int32(s.Index(i)) // permit sign extension to use full 64-bit range
- n += p.valSize(uint64(x))
- }
- return
-}
-
-// Encode a slice of int32s ([]int32) in packed format.
-func (o *Buffer) enc_slice_packed_int32(p *Properties, base structPointer) error {
- s := structPointer_Word32Slice(base, p.field)
- l := s.Len()
- if l == 0 {
- return ErrNil
- }
- // TODO: Reuse a Buffer.
- buf := NewBuffer(nil)
- for i := 0; i < l; i++ {
- x := int32(s.Index(i)) // permit sign extension to use full 64-bit range
- p.valEnc(buf, uint64(x))
- }
-
- o.buf = append(o.buf, p.tagcode...)
- o.EncodeVarint(uint64(len(buf.buf)))
- o.buf = append(o.buf, buf.buf...)
- return nil
-}
-
-func size_slice_packed_int32(p *Properties, base structPointer) (n int) {
- s := structPointer_Word32Slice(base, p.field)
- l := s.Len()
- if l == 0 {
- return 0
- }
- var bufSize int
- for i := 0; i < l; i++ {
- x := int32(s.Index(i)) // permit sign extension to use full 64-bit range
- bufSize += p.valSize(uint64(x))
- }
-
- n += len(p.tagcode)
- n += sizeVarint(uint64(bufSize))
- n += bufSize
- return
-}
-
-// Encode a slice of uint32s ([]uint32).
-// Exactly the same as int32, except for no sign extension.
-func (o *Buffer) enc_slice_uint32(p *Properties, base structPointer) error {
- s := structPointer_Word32Slice(base, p.field)
- l := s.Len()
- if l == 0 {
- return ErrNil
- }
- for i := 0; i < l; i++ {
- o.buf = append(o.buf, p.tagcode...)
- x := s.Index(i)
- p.valEnc(o, uint64(x))
- }
- return nil
-}
-
-func size_slice_uint32(p *Properties, base structPointer) (n int) {
- s := structPointer_Word32Slice(base, p.field)
- l := s.Len()
- if l == 0 {
- return 0
- }
- for i := 0; i < l; i++ {
- n += len(p.tagcode)
- x := s.Index(i)
- n += p.valSize(uint64(x))
- }
- return
-}
-
-// Encode a slice of uint32s ([]uint32) in packed format.
-// Exactly the same as int32, except for no sign extension.
-func (o *Buffer) enc_slice_packed_uint32(p *Properties, base structPointer) error {
- s := structPointer_Word32Slice(base, p.field)
- l := s.Len()
- if l == 0 {
- return ErrNil
- }
- // TODO: Reuse a Buffer.
- buf := NewBuffer(nil)
- for i := 0; i < l; i++ {
- p.valEnc(buf, uint64(s.Index(i)))
- }
-
- o.buf = append(o.buf, p.tagcode...)
- o.EncodeVarint(uint64(len(buf.buf)))
- o.buf = append(o.buf, buf.buf...)
- return nil
-}
-
-func size_slice_packed_uint32(p *Properties, base structPointer) (n int) {
- s := structPointer_Word32Slice(base, p.field)
- l := s.Len()
- if l == 0 {
- return 0
- }
- var bufSize int
- for i := 0; i < l; i++ {
- bufSize += p.valSize(uint64(s.Index(i)))
- }
-
- n += len(p.tagcode)
- n += sizeVarint(uint64(bufSize))
- n += bufSize
- return
-}
-
-// Encode a slice of int64s ([]int64).
-func (o *Buffer) enc_slice_int64(p *Properties, base structPointer) error {
- s := structPointer_Word64Slice(base, p.field)
- l := s.Len()
- if l == 0 {
- return ErrNil
- }
- for i := 0; i < l; i++ {
- o.buf = append(o.buf, p.tagcode...)
- p.valEnc(o, s.Index(i))
- }
- return nil
-}
-
-func size_slice_int64(p *Properties, base structPointer) (n int) {
- s := structPointer_Word64Slice(base, p.field)
- l := s.Len()
- if l == 0 {
- return 0
- }
- for i := 0; i < l; i++ {
- n += len(p.tagcode)
- n += p.valSize(s.Index(i))
- }
- return
-}
-
-// Encode a slice of int64s ([]int64) in packed format.
-func (o *Buffer) enc_slice_packed_int64(p *Properties, base structPointer) error {
- s := structPointer_Word64Slice(base, p.field)
- l := s.Len()
- if l == 0 {
- return ErrNil
- }
- // TODO: Reuse a Buffer.
- buf := NewBuffer(nil)
- for i := 0; i < l; i++ {
- p.valEnc(buf, s.Index(i))
- }
-
- o.buf = append(o.buf, p.tagcode...)
- o.EncodeVarint(uint64(len(buf.buf)))
- o.buf = append(o.buf, buf.buf...)
- return nil
-}
-
-func size_slice_packed_int64(p *Properties, base structPointer) (n int) {
- s := structPointer_Word64Slice(base, p.field)
- l := s.Len()
- if l == 0 {
- return 0
- }
- var bufSize int
- for i := 0; i < l; i++ {
- bufSize += p.valSize(s.Index(i))
- }
-
- n += len(p.tagcode)
- n += sizeVarint(uint64(bufSize))
- n += bufSize
- return
-}
-
-// Encode a slice of slice of bytes ([][]byte).
-func (o *Buffer) enc_slice_slice_byte(p *Properties, base structPointer) error {
- ss := *structPointer_BytesSlice(base, p.field)
- l := len(ss)
- if l == 0 {
- return ErrNil
- }
- for i := 0; i < l; i++ {
- o.buf = append(o.buf, p.tagcode...)
- o.EncodeRawBytes(ss[i])
- }
- return nil
-}
-
-func size_slice_slice_byte(p *Properties, base structPointer) (n int) {
- ss := *structPointer_BytesSlice(base, p.field)
- l := len(ss)
- if l == 0 {
- return 0
- }
- n += l * len(p.tagcode)
- for i := 0; i < l; i++ {
- n += sizeRawBytes(ss[i])
- }
- return
-}
-
-// Encode a slice of strings ([]string).
-func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error {
- ss := *structPointer_StringSlice(base, p.field)
- l := len(ss)
- for i := 0; i < l; i++ {
- o.buf = append(o.buf, p.tagcode...)
- o.EncodeStringBytes(ss[i])
- }
- return nil
-}
-
-func size_slice_string(p *Properties, base structPointer) (n int) {
- ss := *structPointer_StringSlice(base, p.field)
- l := len(ss)
- n += l * len(p.tagcode)
- for i := 0; i < l; i++ {
- n += sizeStringBytes(ss[i])
- }
- return
-}
-
-// Encode a slice of message structs ([]*struct).
-func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error {
- var state errorState
- s := structPointer_StructPointerSlice(base, p.field)
- l := s.Len()
-
- for i := 0; i < l; i++ {
- structp := s.Index(i)
- if structPointer_IsNil(structp) {
- return errRepeatedHasNil
- }
-
- // Can the object marshal itself?
- if p.isMarshaler {
- m := structPointer_Interface(structp, p.stype).(Marshaler)
- data, err := m.Marshal()
- if err != nil && !state.shouldContinue(err, nil) {
- return err
- }
- o.buf = append(o.buf, p.tagcode...)
- o.EncodeRawBytes(data)
- continue
- }
-
- o.buf = append(o.buf, p.tagcode...)
- err := o.enc_len_struct(p.sprop, structp, &state)
- if err != nil && !state.shouldContinue(err, nil) {
- if err == ErrNil {
- return errRepeatedHasNil
- }
- return err
- }
- }
- return state.err
-}
-
-func size_slice_struct_message(p *Properties, base structPointer) (n int) {
- s := structPointer_StructPointerSlice(base, p.field)
- l := s.Len()
- n += l * len(p.tagcode)
- for i := 0; i < l; i++ {
- structp := s.Index(i)
- if structPointer_IsNil(structp) {
- return // return the size up to this point
- }
-
- // Can the object marshal itself?
- if p.isMarshaler {
- m := structPointer_Interface(structp, p.stype).(Marshaler)
- data, _ := m.Marshal()
- n += sizeRawBytes(data)
- continue
- }
-
- n0 := size_struct(p.sprop, structp)
- n1 := sizeVarint(uint64(n0)) // size of encoded length
- n += n0 + n1
- }
- return
-}
-
-// Encode a slice of group structs ([]*struct).
-func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error {
- var state errorState
- s := structPointer_StructPointerSlice(base, p.field)
- l := s.Len()
-
- for i := 0; i < l; i++ {
- b := s.Index(i)
- if structPointer_IsNil(b) {
- return errRepeatedHasNil
- }
-
- o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
-
- err := o.enc_struct(p.sprop, b)
-
- if err != nil && !state.shouldContinue(err, nil) {
- if err == ErrNil {
- return errRepeatedHasNil
- }
- return err
- }
-
- o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
- }
- return state.err
-}
-
-func size_slice_struct_group(p *Properties, base structPointer) (n int) {
- s := structPointer_StructPointerSlice(base, p.field)
- l := s.Len()
-
- n += l * sizeVarint(uint64((p.Tag<<3)|WireStartGroup))
- n += l * sizeVarint(uint64((p.Tag<<3)|WireEndGroup))
- for i := 0; i < l; i++ {
- b := s.Index(i)
- if structPointer_IsNil(b) {
- return // return size up to this point
- }
-
- n += size_struct(p.sprop, b)
- }
- return
-}
-
-// Encode an extension map.
-func (o *Buffer) enc_map(p *Properties, base structPointer) error {
- exts := structPointer_ExtMap(base, p.field)
- if err := encodeExtensionsMap(*exts); err != nil {
- return err
- }
-
- return o.enc_map_body(*exts)
-}
-
-func (o *Buffer) enc_exts(p *Properties, base structPointer) error {
- exts := structPointer_Extensions(base, p.field)
-
- v, mu := exts.extensionsRead()
- if v == nil {
- return nil
- }
-
- mu.Lock()
- defer mu.Unlock()
- if err := encodeExtensionsMap(v); err != nil {
- return err
- }
-
- return o.enc_map_body(v)
-}
-
-func (o *Buffer) enc_map_body(v map[int32]Extension) error {
- // Fast-path for common cases: zero or one extensions.
- if len(v) <= 1 {
- for _, e := range v {
- o.buf = append(o.buf, e.enc...)
- }
- return nil
- }
-
- // Sort keys to provide a deterministic encoding.
- keys := make([]int, 0, len(v))
- for k := range v {
- keys = append(keys, int(k))
- }
- sort.Ints(keys)
-
- for _, k := range keys {
- o.buf = append(o.buf, v[int32(k)].enc...)
- }
- return nil
-}
-
-func size_map(p *Properties, base structPointer) int {
- v := structPointer_ExtMap(base, p.field)
- return extensionsMapSize(*v)
-}
-
-func size_exts(p *Properties, base structPointer) int {
- v := structPointer_Extensions(base, p.field)
- return extensionsSize(v)
-}
-
-// Encode a map field.
-func (o *Buffer) enc_new_map(p *Properties, base structPointer) error {
- var state errorState // XXX: or do we need to plumb this through?
-
- /*
- A map defined as
- map<key_type, value_type> map_field = N;
- is encoded in the same way as
- message MapFieldEntry {
- key_type key = 1;
- value_type value = 2;
- }
- repeated MapFieldEntry map_field = N;
- */
-
- v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V
- if v.Len() == 0 {
- return nil
- }
-
- keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype)
-
- enc := func() error {
- if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil {
- return err
- }
- if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil && err != ErrNil {
- return err
- }
- return nil
- }
-
- // Don't sort map keys. It is not required by the spec, and C++ doesn't do it.
- for _, key := range v.MapKeys() {
- val := v.MapIndex(key)
-
- keycopy.Set(key)
- valcopy.Set(val)
-
- o.buf = append(o.buf, p.tagcode...)
- if err := o.enc_len_thing(enc, &state); err != nil {
- return err
- }
- }
- return nil
-}
-
-func size_new_map(p *Properties, base structPointer) int {
- v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V
-
- keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype)
-
- n := 0
- for _, key := range v.MapKeys() {
- val := v.MapIndex(key)
- keycopy.Set(key)
- valcopy.Set(val)
-
- // Tag codes for key and val are the responsibility of the sub-sizer.
- keysize := p.mkeyprop.size(p.mkeyprop, keybase)
- valsize := p.mvalprop.size(p.mvalprop, valbase)
- entry := keysize + valsize
- // Add on tag code and length of map entry itself.
- n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry
- }
- return n
-}
-
-// mapEncodeScratch returns a new reflect.Value matching the map's value type,
-// and a structPointer suitable for passing to an encoder or sizer.
-func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) {
- // Prepare addressable doubly-indirect placeholders for the key and value types.
- // This is needed because the element-type encoders expect **T, but the map iteration produces T.
-
- keycopy = reflect.New(mapType.Key()).Elem() // addressable K
- keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K
- keyptr.Set(keycopy.Addr()) //
- keybase = toStructPointer(keyptr.Addr()) // **K
-
- // Value types are more varied and require special handling.
- switch mapType.Elem().Kind() {
- case reflect.Slice:
- // []byte
- var dummy []byte
- valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte
- valbase = toStructPointer(valcopy.Addr())
- case reflect.Ptr:
- // message; the generated field type is map[K]*Msg (so V is *Msg),
- // so we only need one level of indirection.
- valcopy = reflect.New(mapType.Elem()).Elem() // addressable V
- valbase = toStructPointer(valcopy.Addr())
- default:
- // everything else
- valcopy = reflect.New(mapType.Elem()).Elem() // addressable V
- valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V
- valptr.Set(valcopy.Addr()) //
- valbase = toStructPointer(valptr.Addr()) // **V
- }
- return
-}
-
-// Encode a struct.
-func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error {
- var state errorState
- // Encode fields in tag order so that decoders may use optimizations
- // that depend on the ordering.
- // https://developers.google.com/protocol-buffers/docs/encoding#order
- for _, i := range prop.order {
- p := prop.Prop[i]
- if p.enc != nil {
- err := p.enc(o, p, base)
- if err != nil {
- if err == ErrNil {
- if p.Required && state.err == nil {
- state.err = &RequiredNotSetError{p.Name}
- }
- } else if err == errRepeatedHasNil {
- // Give more context to nil values in repeated fields.
- return errors.New("repeated field " + p.OrigName + " has nil element")
- } else if !state.shouldContinue(err, p) {
- return err
- }
- }
- if len(o.buf) > maxMarshalSize {
- return ErrTooLarge
- }
- }
- }
-
- // Do oneof fields.
- if prop.oneofMarshaler != nil {
- m := structPointer_Interface(base, prop.stype).(Message)
- if err := prop.oneofMarshaler(m, o); err == ErrNil {
- return errOneofHasNil
- } else if err != nil {
- return err
- }
- }
-
- // Add unrecognized fields at the end.
- if prop.unrecField.IsValid() {
- v := *structPointer_Bytes(base, prop.unrecField)
- if len(o.buf)+len(v) > maxMarshalSize {
- return ErrTooLarge
- }
- if len(v) > 0 {
- o.buf = append(o.buf, v...)
- }
- }
-
- return state.err
-}
-
-func size_struct(prop *StructProperties, base structPointer) (n int) {
- for _, i := range prop.order {
- p := prop.Prop[i]
- if p.size != nil {
- n += p.size(p, base)
- }
- }
-
- // Add unrecognized fields at the end.
- if prop.unrecField.IsValid() {
- v := *structPointer_Bytes(base, prop.unrecField)
- n += len(v)
- }
-
- // Factor in any oneof fields.
- if prop.oneofSizer != nil {
- m := structPointer_Interface(base, prop.stype).(Message)
- n += prop.oneofSizer(m)
- }
-
- return
-}
-
-var zeroes [20]byte // longer than any conceivable sizeVarint
-
-// Encode a struct, preceded by its encoded length (as a varint).
-func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error {
- return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state)
-}
-
-// Encode something, preceded by its encoded length (as a varint).
-func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error {
- iLen := len(o.buf)
- o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length
- iMsg := len(o.buf)
- err := enc()
- if err != nil && !state.shouldContinue(err, nil) {
- return err
- }
- lMsg := len(o.buf) - iMsg
- lLen := sizeVarint(uint64(lMsg))
- switch x := lLen - (iMsg - iLen); {
- case x > 0: // actual length is x bytes larger than the space we reserved
- // Move msg x bytes right.
- o.buf = append(o.buf, zeroes[:x]...)
- copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg])
- case x < 0: // actual length is x bytes smaller than the space we reserved
- // Move msg x bytes left.
- copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg])
- o.buf = o.buf[:len(o.buf)+x] // x is negative
- }
- // Encode the length in the reserved space.
- o.buf = o.buf[:iLen]
- o.EncodeVarint(uint64(lMsg))
- o.buf = o.buf[:len(o.buf)+lMsg]
- return state.err
-}
-
-// errorState maintains the first error that occurs and updates that error
-// with additional context.
-type errorState struct {
- err error
-}
-
-// shouldContinue reports whether encoding should continue upon encountering the
-// given error. If the error is RequiredNotSetError, shouldContinue returns true
-// and, if this is the first appearance of that error, remembers it for future
-// reporting.
-//
-// If prop is not nil, it may update any error with additional context about the
-// field with the error.
-func (s *errorState) shouldContinue(err error, prop *Properties) bool {
- // Ignore unset required fields.
- reqNotSet, ok := err.(*RequiredNotSetError)
- if !ok {
- return false
- }
- if s.err == nil {
- if prop != nil {
- err = &RequiredNotSetError{prop.Name + "." + reqNotSet.field}
- }
- s.err = err
- }
- return true
-}
diff --git a/vendor/github.com/golang/protobuf/proto/equal.go b/vendor/github.com/golang/protobuf/proto/equal.go
index 2ed1cf596..f9b6e41b3 100644
--- a/vendor/github.com/golang/protobuf/proto/equal.go
+++ b/vendor/github.com/golang/protobuf/proto/equal.go
@@ -109,15 +109,6 @@ func equalStruct(v1, v2 reflect.Value) bool {
// set/unset mismatch
return false
}
- b1, ok := f1.Interface().(raw)
- if ok {
- b2 := f2.Interface().(raw)
- // RawMessage
- if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
- return false
- }
- continue
- }
f1, f2 = f1.Elem(), f2.Elem()
}
if !equalAny(f1, f2, sprop.Prop[i]) {
@@ -146,11 +137,7 @@ func equalStruct(v1, v2 reflect.Value) bool {
u1 := uf.Bytes()
u2 := v2.FieldByName("XXX_unrecognized").Bytes()
- if !bytes.Equal(u1, u2) {
- return false
- }
-
- return true
+ return bytes.Equal(u1, u2)
}
// v1 and v2 are known to have the same type.
@@ -259,7 +246,17 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool {
return false
}
- m1, m2 := e1.value, e2.value
+ m1 := extensionAsLegacyType(e1.value)
+ m2 := extensionAsLegacyType(e2.value)
+
+ if m1 == nil && m2 == nil {
+ // Both have only encoded form.
+ if bytes.Equal(e1.enc, e2.enc) {
+ continue
+ }
+ // The bytes are different, but the extensions might still be
+ // equal. We need to decode them to compare.
+ }
if m1 != nil && m2 != nil {
// Both are unencoded.
@@ -276,8 +273,12 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool {
desc = m[extNum]
}
if desc == nil {
+ // If both have only encoded form and the bytes are the same,
+ // it is handled above. We get here when the bytes are different.
+ // We don't know how to decode it, so just compare them as byte
+ // slices.
log.Printf("proto: don't know how to compare extension %d of %v", extNum, base)
- continue
+ return false
}
var err error
if m1 == nil {
diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go
index eaad21831..fa88add30 100644
--- a/vendor/github.com/golang/protobuf/proto/extensions.go
+++ b/vendor/github.com/golang/protobuf/proto/extensions.go
@@ -38,6 +38,7 @@ package proto
import (
"errors"
"fmt"
+ "io"
"reflect"
"strconv"
"sync"
@@ -91,14 +92,29 @@ func (n notLocker) Unlock() {}
// extendable returns the extendableProto interface for the given generated proto message.
// If the proto message has the old extension format, it returns a wrapper that implements
// the extendableProto interface.
-func extendable(p interface{}) (extendableProto, bool) {
- if ep, ok := p.(extendableProto); ok {
- return ep, ok
- }
- if ep, ok := p.(extendableProtoV1); ok {
- return extensionAdapter{ep}, ok
+func extendable(p interface{}) (extendableProto, error) {
+ switch p := p.(type) {
+ case extendableProto:
+ if isNilPtr(p) {
+ return nil, fmt.Errorf("proto: nil %T is not extendable", p)
+ }
+ return p, nil
+ case extendableProtoV1:
+ if isNilPtr(p) {
+ return nil, fmt.Errorf("proto: nil %T is not extendable", p)
+ }
+ return extensionAdapter{p}, nil
}
- return nil, false
+ // Don't allocate a specific error containing %T:
+ // this is the hot path for Clone and MarshalText.
+ return nil, errNotExtendable
+}
+
+var errNotExtendable = errors.New("proto: not an extendable proto.Message")
+
+func isNilPtr(x interface{}) bool {
+ v := reflect.ValueOf(x)
+ return v.Kind() == reflect.Ptr && v.IsNil()
}
// XXX_InternalExtensions is an internal representation of proto extensions.
@@ -143,9 +159,6 @@ func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Loc
return e.p.extensionMap, &e.p.mu
}
-var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem()
-var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem()
-
// ExtensionDesc represents an extension specification.
// Used in generated code from the protocol compiler.
type ExtensionDesc struct {
@@ -172,15 +185,31 @@ type Extension struct {
// extension will have only enc set. When such an extension is
// accessed using GetExtension (or GetExtensions) desc and value
// will be set.
- desc *ExtensionDesc
+ desc *ExtensionDesc
+
+ // value is a concrete value for the extension field. Let the type of
+ // desc.ExtensionType be the "API type" and the type of Extension.value
+ // be the "storage type". The API type and storage type are the same except:
+ // * For scalars (except []byte), the API type uses *T,
+ // while the storage type uses T.
+ // * For repeated fields, the API type uses []T, while the storage type
+ // uses *[]T.
+ //
+ // The reason for the divergence is so that the storage type more naturally
+ // matches what is expected of when retrieving the values through the
+ // protobuf reflection APIs.
+ //
+ // The value may only be populated if desc is also populated.
value interface{}
- enc []byte
+
+ // enc is the raw bytes for the extension field.
+ enc []byte
}
// SetRawExtension is for testing only.
func SetRawExtension(base Message, id int32, b []byte) {
- epb, ok := extendable(base)
- if !ok {
+ epb, err := extendable(base)
+ if err != nil {
return
}
extmap := epb.extensionsWrite()
@@ -205,7 +234,7 @@ func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error {
pbi = ea.extendableProtoV1
}
if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b {
- return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String())
+ return fmt.Errorf("proto: bad extended type; %v does not extend %v", b, a)
}
// Check the range.
if !isExtensionField(pb, extension.Field) {
@@ -250,85 +279,11 @@ func extensionProperties(ed *ExtensionDesc) *Properties {
return prop
}
-// encode encodes any unmarshaled (unencoded) extensions in e.
-func encodeExtensions(e *XXX_InternalExtensions) error {
- m, mu := e.extensionsRead()
- if m == nil {
- return nil // fast path
- }
- mu.Lock()
- defer mu.Unlock()
- return encodeExtensionsMap(m)
-}
-
-// encode encodes any unmarshaled (unencoded) extensions in e.
-func encodeExtensionsMap(m map[int32]Extension) error {
- for k, e := range m {
- if e.value == nil || e.desc == nil {
- // Extension is only in its encoded form.
- continue
- }
-
- // We don't skip extensions that have an encoded form set,
- // because the extension value may have been mutated after
- // the last time this function was called.
-
- et := reflect.TypeOf(e.desc.ExtensionType)
- props := extensionProperties(e.desc)
-
- p := NewBuffer(nil)
- // If e.value has type T, the encoder expects a *struct{ X T }.
- // Pass a *T with a zero field and hope it all works out.
- x := reflect.New(et)
- x.Elem().Set(reflect.ValueOf(e.value))
- if err := props.enc(p, props, toStructPointer(x)); err != nil {
- return err
- }
- e.enc = p.buf
- m[k] = e
- }
- return nil
-}
-
-func extensionsSize(e *XXX_InternalExtensions) (n int) {
- m, mu := e.extensionsRead()
- if m == nil {
- return 0
- }
- mu.Lock()
- defer mu.Unlock()
- return extensionsMapSize(m)
-}
-
-func extensionsMapSize(m map[int32]Extension) (n int) {
- for _, e := range m {
- if e.value == nil || e.desc == nil {
- // Extension is only in its encoded form.
- n += len(e.enc)
- continue
- }
-
- // We don't skip extensions that have an encoded form set,
- // because the extension value may have been mutated after
- // the last time this function was called.
-
- et := reflect.TypeOf(e.desc.ExtensionType)
- props := extensionProperties(e.desc)
-
- // If e.value has type T, the encoder expects a *struct{ X T }.
- // Pass a *T with a zero field and hope it all works out.
- x := reflect.New(et)
- x.Elem().Set(reflect.ValueOf(e.value))
- n += props.size(props, toStructPointer(x))
- }
- return
-}
-
// HasExtension returns whether the given extension is present in pb.
func HasExtension(pb Message, extension *ExtensionDesc) bool {
// TODO: Check types, field numbers, etc.?
- epb, ok := extendable(pb)
- if !ok {
+ epb, err := extendable(pb)
+ if err != nil {
return false
}
extmap, mu := epb.extensionsRead()
@@ -336,15 +291,15 @@ func HasExtension(pb Message, extension *ExtensionDesc) bool {
return false
}
mu.Lock()
- _, ok = extmap[extension.Field]
+ _, ok := extmap[extension.Field]
mu.Unlock()
return ok
}
// ClearExtension removes the given extension from pb.
func ClearExtension(pb Message, extension *ExtensionDesc) {
- epb, ok := extendable(pb)
- if !ok {
+ epb, err := extendable(pb)
+ if err != nil {
return
}
// TODO: Check types, field numbers, etc.?
@@ -352,16 +307,26 @@ func ClearExtension(pb Message, extension *ExtensionDesc) {
delete(extmap, extension.Field)
}
-// GetExtension parses and returns the given extension of pb.
-// If the extension is not present and has no default value it returns ErrMissingExtension.
+// GetExtension retrieves a proto2 extended field from pb.
+//
+// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil),
+// then GetExtension parses the encoded field and returns a Go value of the specified type.
+// If the field is not present, then the default value is returned (if one is specified),
+// otherwise ErrMissingExtension is reported.
+//
+// If the descriptor is not type complete (i.e., ExtensionDesc.ExtensionType is nil),
+// then GetExtension returns the raw encoded bytes of the field extension.
func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
- epb, ok := extendable(pb)
- if !ok {
- return nil, errors.New("proto: not an extendable proto")
+ epb, err := extendable(pb)
+ if err != nil {
+ return nil, err
}
- if err := checkExtensionTypes(epb, extension); err != nil {
- return nil, err
+ if extension.ExtendedType != nil {
+ // can only check type if this is a complete descriptor
+ if err := checkExtensionTypes(epb, extension); err != nil {
+ return nil, err
+ }
}
emap, mu := epb.extensionsRead()
@@ -385,7 +350,12 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
// descriptors with the same field number.
return nil, errors.New("proto: descriptor conflict")
}
- return e.value, nil
+ return extensionAsLegacyType(e.value), nil
+ }
+
+ if extension.ExtensionType == nil {
+ // incomplete descriptor
+ return e.enc, nil
}
v, err := decodeExtension(e.enc, extension)
@@ -395,16 +365,21 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
// Remember the decoded version and drop the encoded version.
// That way it is safe to mutate what we return.
- e.value = v
+ e.value = extensionAsStorageType(v)
e.desc = extension
e.enc = nil
emap[extension.Field] = e
- return e.value, nil
+ return extensionAsLegacyType(e.value), nil
}
// defaultExtensionValue returns the default value for extension.
// If no default for an extension is defined ErrMissingExtension is returned.
func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) {
+ if extension.ExtensionType == nil {
+ // incomplete descriptor, so no default
+ return nil, ErrMissingExtension
+ }
+
t := reflect.TypeOf(extension.ExtensionType)
props := extensionProperties(extension)
@@ -439,31 +414,28 @@ func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) {
// decodeExtension decodes an extension encoded in b.
func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
- o := NewBuffer(b)
-
t := reflect.TypeOf(extension.ExtensionType)
-
- props := extensionProperties(extension)
+ unmarshal := typeUnmarshaler(t, extension.Tag)
// t is a pointer to a struct, pointer to basic type or a slice.
- // Allocate a "field" to store the pointer/slice itself; the
- // pointer/slice will be stored here. We pass
- // the address of this field to props.dec.
- // This passes a zero field and a *t and lets props.dec
- // interpret it as a *struct{ x t }.
+ // Allocate space to store the pointer/slice.
value := reflect.New(t).Elem()
+ var err error
for {
- // Discard wire type and field number varint. It isn't needed.
- if _, err := o.DecodeVarint(); err != nil {
- return nil, err
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
}
+ b = b[n:]
+ wire := int(x) & 7
- if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil {
+ b, err = unmarshal(b, valToPointer(value.Addr()), wire)
+ if err != nil {
return nil, err
}
- if o.index >= len(o.buf) {
+ if len(b) == 0 {
break
}
}
@@ -473,9 +445,9 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
// GetExtensions returns a slice of the extensions present in pb that are also listed in es.
// The returned slice has the same length as es; missing extensions will appear as nil elements.
func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) {
- epb, ok := extendable(pb)
- if !ok {
- return nil, errors.New("proto: not an extendable proto")
+ epb, err := extendable(pb)
+ if err != nil {
+ return nil, err
}
extensions = make([]interface{}, len(es))
for i, e := range es {
@@ -494,9 +466,9 @@ func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, e
// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing
// just the Field field, which defines the extension's field number.
func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) {
- epb, ok := extendable(pb)
- if !ok {
- return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb)
+ epb, err := extendable(pb)
+ if err != nil {
+ return nil, err
}
registeredExtensions := RegisteredExtensions(pb)
@@ -523,16 +495,16 @@ func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) {
// SetExtension sets the specified extension of pb to the specified value.
func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error {
- epb, ok := extendable(pb)
- if !ok {
- return errors.New("proto: not an extendable proto")
+ epb, err := extendable(pb)
+ if err != nil {
+ return err
}
if err := checkExtensionTypes(epb, extension); err != nil {
return err
}
typ := reflect.TypeOf(extension.ExtensionType)
if typ != reflect.TypeOf(value) {
- return errors.New("proto: bad extension value type")
+ return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType)
}
// nil extension values need to be caught early, because the
// encoder can't distinguish an ErrNil due to a nil extension
@@ -544,14 +516,14 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error
}
extmap := epb.extensionsWrite()
- extmap[extension.Field] = Extension{desc: extension, value: value}
+ extmap[extension.Field] = Extension{desc: extension, value: extensionAsStorageType(value)}
return nil
}
// ClearAllExtensions clears all extensions from pb.
func ClearAllExtensions(pb Message) {
- epb, ok := extendable(pb)
- if !ok {
+ epb, err := extendable(pb)
+ if err != nil {
return
}
m := epb.extensionsWrite()
@@ -585,3 +557,51 @@ func RegisterExtension(desc *ExtensionDesc) {
func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc {
return extensionMaps[reflect.TypeOf(pb).Elem()]
}
+
+// extensionAsLegacyType converts an value in the storage type as the API type.
+// See Extension.value.
+func extensionAsLegacyType(v interface{}) interface{} {
+ switch rv := reflect.ValueOf(v); rv.Kind() {
+ case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
+ // Represent primitive types as a pointer to the value.
+ rv2 := reflect.New(rv.Type())
+ rv2.Elem().Set(rv)
+ v = rv2.Interface()
+ case reflect.Ptr:
+ // Represent slice types as the value itself.
+ switch rv.Type().Elem().Kind() {
+ case reflect.Slice:
+ if rv.IsNil() {
+ v = reflect.Zero(rv.Type().Elem()).Interface()
+ } else {
+ v = rv.Elem().Interface()
+ }
+ }
+ }
+ return v
+}
+
+// extensionAsStorageType converts an value in the API type as the storage type.
+// See Extension.value.
+func extensionAsStorageType(v interface{}) interface{} {
+ switch rv := reflect.ValueOf(v); rv.Kind() {
+ case reflect.Ptr:
+ // Represent slice types as the value itself.
+ switch rv.Type().Elem().Kind() {
+ case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
+ if rv.IsNil() {
+ v = reflect.Zero(rv.Type().Elem()).Interface()
+ } else {
+ v = rv.Elem().Interface()
+ }
+ }
+ case reflect.Slice:
+ // Represent slice types as a pointer to the value.
+ if rv.Type().Elem().Kind() != reflect.Uint8 {
+ rv2 := reflect.New(rv.Type())
+ rv2.Elem().Set(rv)
+ v = rv2.Interface()
+ }
+ }
+ return v
+}
diff --git a/vendor/github.com/golang/protobuf/proto/lib.go b/vendor/github.com/golang/protobuf/proto/lib.go
index 1c225504a..fdd328bb7 100644
--- a/vendor/github.com/golang/protobuf/proto/lib.go
+++ b/vendor/github.com/golang/protobuf/proto/lib.go
@@ -273,32 +273,73 @@ import (
"sync"
)
-// Message is implemented by generated protocol buffer messages.
-type Message interface {
- Reset()
- String() string
- ProtoMessage()
+// RequiredNotSetError is an error type returned by either Marshal or Unmarshal.
+// Marshal reports this when a required field is not initialized.
+// Unmarshal reports this when a required field is missing from the wire data.
+type RequiredNotSetError struct{ field string }
+
+func (e *RequiredNotSetError) Error() string {
+ if e.field == "" {
+ return fmt.Sprintf("proto: required field not set")
+ }
+ return fmt.Sprintf("proto: required field %q not set", e.field)
+}
+func (e *RequiredNotSetError) RequiredNotSet() bool {
+ return true
}
-// Stats records allocation details about the protocol buffer encoders
-// and decoders. Useful for tuning the library itself.
-type Stats struct {
- Emalloc uint64 // mallocs in encode
- Dmalloc uint64 // mallocs in decode
- Encode uint64 // number of encodes
- Decode uint64 // number of decodes
- Chit uint64 // number of cache hits
- Cmiss uint64 // number of cache misses
- Size uint64 // number of sizes
+type invalidUTF8Error struct{ field string }
+
+func (e *invalidUTF8Error) Error() string {
+ if e.field == "" {
+ return "proto: invalid UTF-8 detected"
+ }
+ return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field)
+}
+func (e *invalidUTF8Error) InvalidUTF8() bool {
+ return true
}
-// Set to true to enable stats collection.
-const collectStats = false
+// errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8.
+// This error should not be exposed to the external API as such errors should
+// be recreated with the field information.
+var errInvalidUTF8 = &invalidUTF8Error{}
-var stats Stats
+// isNonFatal reports whether the error is either a RequiredNotSet error
+// or a InvalidUTF8 error.
+func isNonFatal(err error) bool {
+ if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() {
+ return true
+ }
+ if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() {
+ return true
+ }
+ return false
+}
-// GetStats returns a copy of the global Stats structure.
-func GetStats() Stats { return stats }
+type nonFatal struct{ E error }
+
+// Merge merges err into nf and reports whether it was successful.
+// Otherwise it returns false for any fatal non-nil errors.
+func (nf *nonFatal) Merge(err error) (ok bool) {
+ if err == nil {
+ return true // not an error
+ }
+ if !isNonFatal(err) {
+ return false // fatal error
+ }
+ if nf.E == nil {
+ nf.E = err // store first instance of non-fatal error
+ }
+ return true
+}
+
+// Message is implemented by generated protocol buffer messages.
+type Message interface {
+ Reset()
+ String() string
+ ProtoMessage()
+}
// A Buffer is a buffer manager for marshaling and unmarshaling
// protocol buffers. It may be reused between invocations to
@@ -309,16 +350,7 @@ type Buffer struct {
buf []byte // encode/decode byte stream
index int // read point
- // pools of basic types to amortize allocation.
- bools []bool
- uint32s []uint32
- uint64s []uint64
-
- // extra pools, only used with pointer_reflect.go
- int32s []int32
- int64s []int64
- float32s []float32
- float64s []float64
+ deterministic bool
}
// NewBuffer allocates a new Buffer and initializes its internal data to
@@ -343,6 +375,30 @@ func (p *Buffer) SetBuf(s []byte) {
// Bytes returns the contents of the Buffer.
func (p *Buffer) Bytes() []byte { return p.buf }
+// SetDeterministic sets whether to use deterministic serialization.
+//
+// Deterministic serialization guarantees that for a given binary, equal
+// messages will always be serialized to the same bytes. This implies:
+//
+// - Repeated serialization of a message will return the same bytes.
+// - Different processes of the same binary (which may be executing on
+// different machines) will serialize equal messages to the same bytes.
+//
+// Note that the deterministic serialization is NOT canonical across
+// languages. It is not guaranteed to remain stable over time. It is unstable
+// across different builds with schema changes due to unknown fields.
+// Users who need canonical serialization (e.g., persistent storage in a
+// canonical form, fingerprinting, etc.) should define their own
+// canonicalization specification and implement their own serializer rather
+// than relying on this API.
+//
+// If deterministic serialization is requested, map entries will be sorted
+// by keys in lexographical order. This is an implementation detail and
+// subject to change.
+func (p *Buffer) SetDeterministic(deterministic bool) {
+ p.deterministic = deterministic
+}
+
/*
* Helper routines for simplifying the creation of optional fields of basic type.
*/
@@ -831,22 +887,12 @@ func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMes
return sf, false, nil
}
+// mapKeys returns a sort.Interface to be used for sorting the map keys.
// Map fields may have key types of non-float scalars, strings and enums.
-// The easiest way to sort them in some deterministic order is to use fmt.
-// If this turns out to be inefficient we can always consider other options,
-// such as doing a Schwartzian transform.
-
func mapKeys(vs []reflect.Value) sort.Interface {
- s := mapKeySorter{
- vs: vs,
- // default Less function: textual comparison
- less: func(a, b reflect.Value) bool {
- return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface())
- },
- }
+ s := mapKeySorter{vs: vs}
- // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps;
- // numeric keys are sorted numerically.
+ // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps.
if len(vs) == 0 {
return s
}
@@ -855,6 +901,12 @@ func mapKeys(vs []reflect.Value) sort.Interface {
s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() }
case reflect.Uint32, reflect.Uint64:
s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() }
+ case reflect.Bool:
+ s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true
+ case reflect.String:
+ s.less = func(a, b reflect.Value) bool { return a.String() < b.String() }
+ default:
+ panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind()))
}
return s
@@ -888,10 +940,26 @@ func isProto3Zero(v reflect.Value) bool {
return false
}
-// ProtoPackageIsVersion2 is referenced from generated protocol buffer files
-// to assert that that code is compatible with this version of the proto package.
-const ProtoPackageIsVersion2 = true
+const (
+ // ProtoPackageIsVersion3 is referenced from generated protocol buffer files
+ // to assert that that code is compatible with this version of the proto package.
+ ProtoPackageIsVersion3 = true
+
+ // ProtoPackageIsVersion2 is referenced from generated protocol buffer files
+ // to assert that that code is compatible with this version of the proto package.
+ ProtoPackageIsVersion2 = true
-// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
-// to assert that that code is compatible with this version of the proto package.
-const ProtoPackageIsVersion1 = true
+ // ProtoPackageIsVersion1 is referenced from generated protocol buffer files
+ // to assert that that code is compatible with this version of the proto package.
+ ProtoPackageIsVersion1 = true
+)
+
+// InternalMessageInfo is a type used internally by generated .pb.go files.
+// This type is not intended to be used by non-generated code.
+// This type is not subject to any compatibility guarantee.
+type InternalMessageInfo struct {
+ marshal *marshalInfo
+ unmarshal *unmarshalInfo
+ merge *mergeInfo
+ discard *discardInfo
+}
diff --git a/vendor/github.com/golang/protobuf/proto/message_set.go b/vendor/github.com/golang/protobuf/proto/message_set.go
index fd982decd..f48a75676 100644
--- a/vendor/github.com/golang/protobuf/proto/message_set.go
+++ b/vendor/github.com/golang/protobuf/proto/message_set.go
@@ -36,12 +36,7 @@ package proto
*/
import (
- "bytes"
- "encoding/json"
"errors"
- "fmt"
- "reflect"
- "sort"
)
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
@@ -94,10 +89,7 @@ func (ms *messageSet) find(pb Message) *_MessageSet_Item {
}
func (ms *messageSet) Has(pb Message) bool {
- if ms.find(pb) != nil {
- return true
- }
- return false
+ return ms.find(pb) != nil
}
func (ms *messageSet) Unmarshal(pb Message) error {
@@ -147,50 +139,9 @@ func skipVarint(buf []byte) []byte {
return buf[i+1:]
}
-// MarshalMessageSet encodes the extension map represented by m in the message set wire format.
-// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
-func MarshalMessageSet(exts interface{}) ([]byte, error) {
- var m map[int32]Extension
- switch exts := exts.(type) {
- case *XXX_InternalExtensions:
- if err := encodeExtensions(exts); err != nil {
- return nil, err
- }
- m, _ = exts.extensionsRead()
- case map[int32]Extension:
- if err := encodeExtensionsMap(exts); err != nil {
- return nil, err
- }
- m = exts
- default:
- return nil, errors.New("proto: not an extension map")
- }
-
- // Sort extension IDs to provide a deterministic encoding.
- // See also enc_map in encode.go.
- ids := make([]int, 0, len(m))
- for id := range m {
- ids = append(ids, int(id))
- }
- sort.Ints(ids)
-
- ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
- for _, id := range ids {
- e := m[int32(id)]
- // Remove the wire type and field number varint, as well as the length varint.
- msg := skipVarint(skipVarint(e.enc))
-
- ms.Item = append(ms.Item, &_MessageSet_Item{
- TypeId: Int32(int32(id)),
- Message: msg,
- })
- }
- return Marshal(ms)
-}
-
-// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
-// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
-func UnmarshalMessageSet(buf []byte, exts interface{}) error {
+// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
+// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
+func unmarshalMessageSet(buf []byte, exts interface{}) error {
var m map[int32]Extension
switch exts := exts.(type) {
case *XXX_InternalExtensions:
@@ -228,84 +179,3 @@ func UnmarshalMessageSet(buf []byte, exts interface{}) error {
}
return nil
}
-
-// MarshalMessageSetJSON encodes the extension map represented by m in JSON format.
-// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
-func MarshalMessageSetJSON(exts interface{}) ([]byte, error) {
- var m map[int32]Extension
- switch exts := exts.(type) {
- case *XXX_InternalExtensions:
- m, _ = exts.extensionsRead()
- case map[int32]Extension:
- m = exts
- default:
- return nil, errors.New("proto: not an extension map")
- }
- var b bytes.Buffer
- b.WriteByte('{')
-
- // Process the map in key order for deterministic output.
- ids := make([]int32, 0, len(m))
- for id := range m {
- ids = append(ids, id)
- }
- sort.Sort(int32Slice(ids)) // int32Slice defined in text.go
-
- for i, id := range ids {
- ext := m[id]
- if i > 0 {
- b.WriteByte(',')
- }
-
- msd, ok := messageSetMap[id]
- if !ok {
- // Unknown type; we can't render it, so skip it.
- continue
- }
- fmt.Fprintf(&b, `"[%s]":`, msd.name)
-
- x := ext.value
- if x == nil {
- x = reflect.New(msd.t.Elem()).Interface()
- if err := Unmarshal(ext.enc, x.(Message)); err != nil {
- return nil, err
- }
- }
- d, err := json.Marshal(x)
- if err != nil {
- return nil, err
- }
- b.Write(d)
- }
- b.WriteByte('}')
- return b.Bytes(), nil
-}
-
-// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format.
-// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
-func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error {
- // Common-case fast path.
- if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) {
- return nil
- }
-
- // This is fairly tricky, and it's not clear that it is needed.
- return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented")
-}
-
-// A global registry of types that can be used in a MessageSet.
-
-var messageSetMap = make(map[int32]messageSetDesc)
-
-type messageSetDesc struct {
- t reflect.Type // pointer to struct
- name string
-}
-
-// RegisterMessageSetType is called from the generated code.
-func RegisterMessageSetType(m Message, fieldNum int32, name string) {
- messageSetMap[fieldNum] = messageSetDesc{
- t: reflect.TypeOf(m),
- name: name,
- }
-}
diff --git a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go
index fb512e2e1..94fa9194a 100644
--- a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go
+++ b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go
@@ -29,7 +29,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// +build appengine js
+// +build purego appengine js
// This file contains an implementation of proto field accesses using package reflect.
// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can
@@ -38,32 +38,13 @@
package proto
import (
- "math"
"reflect"
+ "sync"
)
-// A structPointer is a pointer to a struct.
-type structPointer struct {
- v reflect.Value
-}
-
-// toStructPointer returns a structPointer equivalent to the given reflect value.
-// The reflect value must itself be a pointer to a struct.
-func toStructPointer(v reflect.Value) structPointer {
- return structPointer{v}
-}
-
-// IsNil reports whether p is nil.
-func structPointer_IsNil(p structPointer) bool {
- return p.v.IsNil()
-}
+const unsafeAllowed = false
-// Interface returns the struct pointer as an interface value.
-func structPointer_Interface(p structPointer, _ reflect.Type) interface{} {
- return p.v.Interface()
-}
-
-// A field identifies a field in a struct, accessible from a structPointer.
+// A field identifies a field in a struct, accessible from a pointer.
// In this implementation, a field is identified by the sequence of field indices
// passed to reflect's FieldByIndex.
type field []int
@@ -76,409 +57,304 @@ func toField(f *reflect.StructField) field {
// invalidField is an invalid field identifier.
var invalidField = field(nil)
+// zeroField is a noop when calling pointer.offset.
+var zeroField = field([]int{})
+
// IsValid reports whether the field identifier is valid.
func (f field) IsValid() bool { return f != nil }
-// field returns the given field in the struct as a reflect value.
-func structPointer_field(p structPointer, f field) reflect.Value {
- // Special case: an extension map entry with a value of type T
- // passes a *T to the struct-handling code with a zero field,
- // expecting that it will be treated as equivalent to *struct{ X T },
- // which has the same memory layout. We have to handle that case
- // specially, because reflect will panic if we call FieldByIndex on a
- // non-struct.
- if f == nil {
- return p.v.Elem()
- }
-
- return p.v.Elem().FieldByIndex(f)
+// The pointer type is for the table-driven decoder.
+// The implementation here uses a reflect.Value of pointer type to
+// create a generic pointer. In pointer_unsafe.go we use unsafe
+// instead of reflect to implement the same (but faster) interface.
+type pointer struct {
+ v reflect.Value
}
-// ifield returns the given field in the struct as an interface value.
-func structPointer_ifield(p structPointer, f field) interface{} {
- return structPointer_field(p, f).Addr().Interface()
+// toPointer converts an interface of pointer type to a pointer
+// that points to the same target.
+func toPointer(i *Message) pointer {
+ return pointer{v: reflect.ValueOf(*i)}
}
-// Bytes returns the address of a []byte field in the struct.
-func structPointer_Bytes(p structPointer, f field) *[]byte {
- return structPointer_ifield(p, f).(*[]byte)
+// toAddrPointer converts an interface to a pointer that points to
+// the interface data.
+func toAddrPointer(i *interface{}, isptr, deref bool) pointer {
+ v := reflect.ValueOf(*i)
+ u := reflect.New(v.Type())
+ u.Elem().Set(v)
+ if deref {
+ u = u.Elem()
+ }
+ return pointer{v: u}
}
-// BytesSlice returns the address of a [][]byte field in the struct.
-func structPointer_BytesSlice(p structPointer, f field) *[][]byte {
- return structPointer_ifield(p, f).(*[][]byte)
+// valToPointer converts v to a pointer. v must be of pointer type.
+func valToPointer(v reflect.Value) pointer {
+ return pointer{v: v}
}
-// Bool returns the address of a *bool field in the struct.
-func structPointer_Bool(p structPointer, f field) **bool {
- return structPointer_ifield(p, f).(**bool)
+// offset converts from a pointer to a structure to a pointer to
+// one of its fields.
+func (p pointer) offset(f field) pointer {
+ return pointer{v: p.v.Elem().FieldByIndex(f).Addr()}
}
-// BoolVal returns the address of a bool field in the struct.
-func structPointer_BoolVal(p structPointer, f field) *bool {
- return structPointer_ifield(p, f).(*bool)
+func (p pointer) isNil() bool {
+ return p.v.IsNil()
}
-// BoolSlice returns the address of a []bool field in the struct.
-func structPointer_BoolSlice(p structPointer, f field) *[]bool {
- return structPointer_ifield(p, f).(*[]bool)
+// grow updates the slice s in place to make it one element longer.
+// s must be addressable.
+// Returns the (addressable) new element.
+func grow(s reflect.Value) reflect.Value {
+ n, m := s.Len(), s.Cap()
+ if n < m {
+ s.SetLen(n + 1)
+ } else {
+ s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem())))
+ }
+ return s.Index(n)
}
-// String returns the address of a *string field in the struct.
-func structPointer_String(p structPointer, f field) **string {
- return structPointer_ifield(p, f).(**string)
+func (p pointer) toInt64() *int64 {
+ return p.v.Interface().(*int64)
}
-
-// StringVal returns the address of a string field in the struct.
-func structPointer_StringVal(p structPointer, f field) *string {
- return structPointer_ifield(p, f).(*string)
+func (p pointer) toInt64Ptr() **int64 {
+ return p.v.Interface().(**int64)
}
-
-// StringSlice returns the address of a []string field in the struct.
-func structPointer_StringSlice(p structPointer, f field) *[]string {
- return structPointer_ifield(p, f).(*[]string)
+func (p pointer) toInt64Slice() *[]int64 {
+ return p.v.Interface().(*[]int64)
}
-// Extensions returns the address of an extension map field in the struct.
-func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions {
- return structPointer_ifield(p, f).(*XXX_InternalExtensions)
-}
+var int32ptr = reflect.TypeOf((*int32)(nil))
-// ExtMap returns the address of an extension map field in the struct.
-func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
- return structPointer_ifield(p, f).(*map[int32]Extension)
+func (p pointer) toInt32() *int32 {
+ return p.v.Convert(int32ptr).Interface().(*int32)
}
-// NewAt returns the reflect.Value for a pointer to a field in the struct.
-func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value {
- return structPointer_field(p, f).Addr()
+// The toInt32Ptr/Slice methods don't work because of enums.
+// Instead, we must use set/get methods for the int32ptr/slice case.
+/*
+ func (p pointer) toInt32Ptr() **int32 {
+ return p.v.Interface().(**int32)
}
-
-// SetStructPointer writes a *struct field in the struct.
-func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
- structPointer_field(p, f).Set(q.v)
+ func (p pointer) toInt32Slice() *[]int32 {
+ return p.v.Interface().(*[]int32)
}
-
-// GetStructPointer reads a *struct field in the struct.
-func structPointer_GetStructPointer(p structPointer, f field) structPointer {
- return structPointer{structPointer_field(p, f)}
+*/
+func (p pointer) getInt32Ptr() *int32 {
+ if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) {
+ // raw int32 type
+ return p.v.Elem().Interface().(*int32)
+ }
+ // an enum
+ return p.v.Elem().Convert(int32PtrType).Interface().(*int32)
+}
+func (p pointer) setInt32Ptr(v int32) {
+ // Allocate value in a *int32. Possibly convert that to a *enum.
+ // Then assign it to a **int32 or **enum.
+ // Note: we can convert *int32 to *enum, but we can't convert
+ // **int32 to **enum!
+ p.v.Elem().Set(reflect.ValueOf(&v).Convert(p.v.Type().Elem()))
+}
+
+// getInt32Slice copies []int32 from p as a new slice.
+// This behavior differs from the implementation in pointer_unsafe.go.
+func (p pointer) getInt32Slice() []int32 {
+ if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) {
+ // raw int32 type
+ return p.v.Elem().Interface().([]int32)
+ }
+ // an enum
+ // Allocate a []int32, then assign []enum's values into it.
+ // Note: we can't convert []enum to []int32.
+ slice := p.v.Elem()
+ s := make([]int32, slice.Len())
+ for i := 0; i < slice.Len(); i++ {
+ s[i] = int32(slice.Index(i).Int())
+ }
+ return s
}
-// StructPointerSlice the address of a []*struct field in the struct.
-func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice {
- return structPointerSlice{structPointer_field(p, f)}
+// setInt32Slice copies []int32 into p as a new slice.
+// This behavior differs from the implementation in pointer_unsafe.go.
+func (p pointer) setInt32Slice(v []int32) {
+ if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) {
+ // raw int32 type
+ p.v.Elem().Set(reflect.ValueOf(v))
+ return
+ }
+ // an enum
+ // Allocate a []enum, then assign []int32's values into it.
+ // Note: we can't convert []enum to []int32.
+ slice := reflect.MakeSlice(p.v.Type().Elem(), len(v), cap(v))
+ for i, x := range v {
+ slice.Index(i).SetInt(int64(x))
+ }
+ p.v.Elem().Set(slice)
}
-
-// A structPointerSlice represents the address of a slice of pointers to structs
-// (themselves messages or groups). That is, v.Type() is *[]*struct{...}.
-type structPointerSlice struct {
- v reflect.Value
+func (p pointer) appendInt32Slice(v int32) {
+ grow(p.v.Elem()).SetInt(int64(v))
}
-func (p structPointerSlice) Len() int { return p.v.Len() }
-func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} }
-func (p structPointerSlice) Append(q structPointer) {
- p.v.Set(reflect.Append(p.v, q.v))
+func (p pointer) toUint64() *uint64 {
+ return p.v.Interface().(*uint64)
}
-
-var (
- int32Type = reflect.TypeOf(int32(0))
- uint32Type = reflect.TypeOf(uint32(0))
- float32Type = reflect.TypeOf(float32(0))
- int64Type = reflect.TypeOf(int64(0))
- uint64Type = reflect.TypeOf(uint64(0))
- float64Type = reflect.TypeOf(float64(0))
-)
-
-// A word32 represents a field of type *int32, *uint32, *float32, or *enum.
-// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable.
-type word32 struct {
- v reflect.Value
+func (p pointer) toUint64Ptr() **uint64 {
+ return p.v.Interface().(**uint64)
}
-
-// IsNil reports whether p is nil.
-func word32_IsNil(p word32) bool {
- return p.v.IsNil()
+func (p pointer) toUint64Slice() *[]uint64 {
+ return p.v.Interface().(*[]uint64)
}
-
-// Set sets p to point at a newly allocated word with bits set to x.
-func word32_Set(p word32, o *Buffer, x uint32) {
- t := p.v.Type().Elem()
- switch t {
- case int32Type:
- if len(o.int32s) == 0 {
- o.int32s = make([]int32, uint32PoolSize)
- }
- o.int32s[0] = int32(x)
- p.v.Set(reflect.ValueOf(&o.int32s[0]))
- o.int32s = o.int32s[1:]
- return
- case uint32Type:
- if len(o.uint32s) == 0 {
- o.uint32s = make([]uint32, uint32PoolSize)
- }
- o.uint32s[0] = x
- p.v.Set(reflect.ValueOf(&o.uint32s[0]))
- o.uint32s = o.uint32s[1:]
- return
- case float32Type:
- if len(o.float32s) == 0 {
- o.float32s = make([]float32, uint32PoolSize)
- }
- o.float32s[0] = math.Float32frombits(x)
- p.v.Set(reflect.ValueOf(&o.float32s[0]))
- o.float32s = o.float32s[1:]
- return
- }
-
- // must be enum
- p.v.Set(reflect.New(t))
- p.v.Elem().SetInt(int64(int32(x)))
+func (p pointer) toUint32() *uint32 {
+ return p.v.Interface().(*uint32)
}
-
-// Get gets the bits pointed at by p, as a uint32.
-func word32_Get(p word32) uint32 {
- elem := p.v.Elem()
- switch elem.Kind() {
- case reflect.Int32:
- return uint32(elem.Int())
- case reflect.Uint32:
- return uint32(elem.Uint())
- case reflect.Float32:
- return math.Float32bits(float32(elem.Float()))
- }
- panic("unreachable")
+func (p pointer) toUint32Ptr() **uint32 {
+ return p.v.Interface().(**uint32)
}
-
-// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct.
-func structPointer_Word32(p structPointer, f field) word32 {
- return word32{structPointer_field(p, f)}
+func (p pointer) toUint32Slice() *[]uint32 {
+ return p.v.Interface().(*[]uint32)
}
-
-// A word32Val represents a field of type int32, uint32, float32, or enum.
-// That is, v.Type() is int32, uint32, float32, or enum and v is assignable.
-type word32Val struct {
- v reflect.Value
+func (p pointer) toBool() *bool {
+ return p.v.Interface().(*bool)
}
-
-// Set sets *p to x.
-func word32Val_Set(p word32Val, x uint32) {
- switch p.v.Type() {
- case int32Type:
- p.v.SetInt(int64(x))
- return
- case uint32Type:
- p.v.SetUint(uint64(x))
- return
- case float32Type:
- p.v.SetFloat(float64(math.Float32frombits(x)))
- return
- }
-
- // must be enum
- p.v.SetInt(int64(int32(x)))
+func (p pointer) toBoolPtr() **bool {
+ return p.v.Interface().(**bool)
}
-
-// Get gets the bits pointed at by p, as a uint32.
-func word32Val_Get(p word32Val) uint32 {
- elem := p.v
- switch elem.Kind() {
- case reflect.Int32:
- return uint32(elem.Int())
- case reflect.Uint32:
- return uint32(elem.Uint())
- case reflect.Float32:
- return math.Float32bits(float32(elem.Float()))
- }
- panic("unreachable")
+func (p pointer) toBoolSlice() *[]bool {
+ return p.v.Interface().(*[]bool)
}
-
-// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct.
-func structPointer_Word32Val(p structPointer, f field) word32Val {
- return word32Val{structPointer_field(p, f)}
+func (p pointer) toFloat64() *float64 {
+ return p.v.Interface().(*float64)
}
-
-// A word32Slice is a slice of 32-bit values.
-// That is, v.Type() is []int32, []uint32, []float32, or []enum.
-type word32Slice struct {
- v reflect.Value
+func (p pointer) toFloat64Ptr() **float64 {
+ return p.v.Interface().(**float64)
}
-
-func (p word32Slice) Append(x uint32) {
- n, m := p.v.Len(), p.v.Cap()
- if n < m {
- p.v.SetLen(n + 1)
- } else {
- t := p.v.Type().Elem()
- p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
- }
- elem := p.v.Index(n)
- switch elem.Kind() {
- case reflect.Int32:
- elem.SetInt(int64(int32(x)))
- case reflect.Uint32:
- elem.SetUint(uint64(x))
- case reflect.Float32:
- elem.SetFloat(float64(math.Float32frombits(x)))
- }
+func (p pointer) toFloat64Slice() *[]float64 {
+ return p.v.Interface().(*[]float64)
}
-
-func (p word32Slice) Len() int {
- return p.v.Len()
+func (p pointer) toFloat32() *float32 {
+ return p.v.Interface().(*float32)
}
-
-func (p word32Slice) Index(i int) uint32 {
- elem := p.v.Index(i)
- switch elem.Kind() {
- case reflect.Int32:
- return uint32(elem.Int())
- case reflect.Uint32:
- return uint32(elem.Uint())
- case reflect.Float32:
- return math.Float32bits(float32(elem.Float()))
- }
- panic("unreachable")
+func (p pointer) toFloat32Ptr() **float32 {
+ return p.v.Interface().(**float32)
}
-
-// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct.
-func structPointer_Word32Slice(p structPointer, f field) word32Slice {
- return word32Slice{structPointer_field(p, f)}
+func (p pointer) toFloat32Slice() *[]float32 {
+ return p.v.Interface().(*[]float32)
}
-
-// word64 is like word32 but for 64-bit values.
-type word64 struct {
- v reflect.Value
+func (p pointer) toString() *string {
+ return p.v.Interface().(*string)
}
-
-func word64_Set(p word64, o *Buffer, x uint64) {
- t := p.v.Type().Elem()
- switch t {
- case int64Type:
- if len(o.int64s) == 0 {
- o.int64s = make([]int64, uint64PoolSize)
- }
- o.int64s[0] = int64(x)
- p.v.Set(reflect.ValueOf(&o.int64s[0]))
- o.int64s = o.int64s[1:]
- return
- case uint64Type:
- if len(o.uint64s) == 0 {
- o.uint64s = make([]uint64, uint64PoolSize)
- }
- o.uint64s[0] = x
- p.v.Set(reflect.ValueOf(&o.uint64s[0]))
- o.uint64s = o.uint64s[1:]
- return
- case float64Type:
- if len(o.float64s) == 0 {
- o.float64s = make([]float64, uint64PoolSize)
- }
- o.float64s[0] = math.Float64frombits(x)
- p.v.Set(reflect.ValueOf(&o.float64s[0]))
- o.float64s = o.float64s[1:]
- return
- }
- panic("unreachable")
+func (p pointer) toStringPtr() **string {
+ return p.v.Interface().(**string)
}
-
-func word64_IsNil(p word64) bool {
- return p.v.IsNil()
+func (p pointer) toStringSlice() *[]string {
+ return p.v.Interface().(*[]string)
}
-
-func word64_Get(p word64) uint64 {
- elem := p.v.Elem()
- switch elem.Kind() {
- case reflect.Int64:
- return uint64(elem.Int())
- case reflect.Uint64:
- return elem.Uint()
- case reflect.Float64:
- return math.Float64bits(elem.Float())
- }
- panic("unreachable")
+func (p pointer) toBytes() *[]byte {
+ return p.v.Interface().(*[]byte)
}
-
-func structPointer_Word64(p structPointer, f field) word64 {
- return word64{structPointer_field(p, f)}
+func (p pointer) toBytesSlice() *[][]byte {
+ return p.v.Interface().(*[][]byte)
+}
+func (p pointer) toExtensions() *XXX_InternalExtensions {
+ return p.v.Interface().(*XXX_InternalExtensions)
+}
+func (p pointer) toOldExtensions() *map[int32]Extension {
+ return p.v.Interface().(*map[int32]Extension)
+}
+func (p pointer) getPointer() pointer {
+ return pointer{v: p.v.Elem()}
+}
+func (p pointer) setPointer(q pointer) {
+ p.v.Elem().Set(q.v)
+}
+func (p pointer) appendPointer(q pointer) {
+ grow(p.v.Elem()).Set(q.v)
}
-// word64Val is like word32Val but for 64-bit values.
-type word64Val struct {
- v reflect.Value
+// getPointerSlice copies []*T from p as a new []pointer.
+// This behavior differs from the implementation in pointer_unsafe.go.
+func (p pointer) getPointerSlice() []pointer {
+ if p.v.IsNil() {
+ return nil
+ }
+ n := p.v.Elem().Len()
+ s := make([]pointer, n)
+ for i := 0; i < n; i++ {
+ s[i] = pointer{v: p.v.Elem().Index(i)}
+ }
+ return s
}
-func word64Val_Set(p word64Val, o *Buffer, x uint64) {
- switch p.v.Type() {
- case int64Type:
- p.v.SetInt(int64(x))
- return
- case uint64Type:
- p.v.SetUint(x)
- return
- case float64Type:
- p.v.SetFloat(math.Float64frombits(x))
+// setPointerSlice copies []pointer into p as a new []*T.
+// This behavior differs from the implementation in pointer_unsafe.go.
+func (p pointer) setPointerSlice(v []pointer) {
+ if v == nil {
+ p.v.Elem().Set(reflect.New(p.v.Elem().Type()).Elem())
return
}
- panic("unreachable")
+ s := reflect.MakeSlice(p.v.Elem().Type(), 0, len(v))
+ for _, p := range v {
+ s = reflect.Append(s, p.v)
+ }
+ p.v.Elem().Set(s)
}
-func word64Val_Get(p word64Val) uint64 {
- elem := p.v
- switch elem.Kind() {
- case reflect.Int64:
- return uint64(elem.Int())
- case reflect.Uint64:
- return elem.Uint()
- case reflect.Float64:
- return math.Float64bits(elem.Float())
+// getInterfacePointer returns a pointer that points to the
+// interface data of the interface pointed by p.
+func (p pointer) getInterfacePointer() pointer {
+ if p.v.Elem().IsNil() {
+ return pointer{v: p.v.Elem()}
}
- panic("unreachable")
+ return pointer{v: p.v.Elem().Elem().Elem().Field(0).Addr()} // *interface -> interface -> *struct -> struct
}
-func structPointer_Word64Val(p structPointer, f field) word64Val {
- return word64Val{structPointer_field(p, f)}
+func (p pointer) asPointerTo(t reflect.Type) reflect.Value {
+ // TODO: check that p.v.Type().Elem() == t?
+ return p.v
}
-type word64Slice struct {
- v reflect.Value
+func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo {
+ atomicLock.Lock()
+ defer atomicLock.Unlock()
+ return *p
}
-
-func (p word64Slice) Append(x uint64) {
- n, m := p.v.Len(), p.v.Cap()
- if n < m {
- p.v.SetLen(n + 1)
- } else {
- t := p.v.Type().Elem()
- p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
- }
- elem := p.v.Index(n)
- switch elem.Kind() {
- case reflect.Int64:
- elem.SetInt(int64(int64(x)))
- case reflect.Uint64:
- elem.SetUint(uint64(x))
- case reflect.Float64:
- elem.SetFloat(float64(math.Float64frombits(x)))
- }
+func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) {
+ atomicLock.Lock()
+ defer atomicLock.Unlock()
+ *p = v
}
-
-func (p word64Slice) Len() int {
- return p.v.Len()
+func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo {
+ atomicLock.Lock()
+ defer atomicLock.Unlock()
+ return *p
}
-
-func (p word64Slice) Index(i int) uint64 {
- elem := p.v.Index(i)
- switch elem.Kind() {
- case reflect.Int64:
- return uint64(elem.Int())
- case reflect.Uint64:
- return uint64(elem.Uint())
- case reflect.Float64:
- return math.Float64bits(float64(elem.Float()))
- }
- panic("unreachable")
+func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) {
+ atomicLock.Lock()
+ defer atomicLock.Unlock()
+ *p = v
}
-
-func structPointer_Word64Slice(p structPointer, f field) word64Slice {
- return word64Slice{structPointer_field(p, f)}
+func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo {
+ atomicLock.Lock()
+ defer atomicLock.Unlock()
+ return *p
+}
+func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) {
+ atomicLock.Lock()
+ defer atomicLock.Unlock()
+ *p = v
}
+func atomicLoadDiscardInfo(p **discardInfo) *discardInfo {
+ atomicLock.Lock()
+ defer atomicLock.Unlock()
+ return *p
+}
+func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) {
+ atomicLock.Lock()
+ defer atomicLock.Unlock()
+ *p = v
+}
+
+var atomicLock sync.Mutex
diff --git a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go
index 6b5567d47..dbfffe071 100644
--- a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go
+++ b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go
@@ -29,7 +29,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// +build !appengine,!js
+// +build !purego,!appengine,!js
// This file contains the implementation of the proto field accesses using package unsafe.
@@ -37,38 +37,13 @@ package proto
import (
"reflect"
+ "sync/atomic"
"unsafe"
)
-// NOTE: These type_Foo functions would more idiomatically be methods,
-// but Go does not allow methods on pointer types, and we must preserve
-// some pointer type for the garbage collector. We use these
-// funcs with clunky names as our poor approximation to methods.
-//
-// An alternative would be
-// type structPointer struct { p unsafe.Pointer }
-// but that does not registerize as well.
-
-// A structPointer is a pointer to a struct.
-type structPointer unsafe.Pointer
-
-// toStructPointer returns a structPointer equivalent to the given reflect value.
-func toStructPointer(v reflect.Value) structPointer {
- return structPointer(unsafe.Pointer(v.Pointer()))
-}
-
-// IsNil reports whether p is nil.
-func structPointer_IsNil(p structPointer) bool {
- return p == nil
-}
-
-// Interface returns the struct pointer, assumed to have element type t,
-// as an interface value.
-func structPointer_Interface(p structPointer, t reflect.Type) interface{} {
- return reflect.NewAt(t, unsafe.Pointer(p)).Interface()
-}
+const unsafeAllowed = true
-// A field identifies a field in a struct, accessible from a structPointer.
+// A field identifies a field in a struct, accessible from a pointer.
// In this implementation, a field is identified by its byte offset from the start of the struct.
type field uintptr
@@ -80,191 +55,259 @@ func toField(f *reflect.StructField) field {
// invalidField is an invalid field identifier.
const invalidField = ^field(0)
+// zeroField is a noop when calling pointer.offset.
+const zeroField = field(0)
+
// IsValid reports whether the field identifier is valid.
func (f field) IsValid() bool {
- return f != ^field(0)
+ return f != invalidField
+}
+
+// The pointer type below is for the new table-driven encoder/decoder.
+// The implementation here uses unsafe.Pointer to create a generic pointer.
+// In pointer_reflect.go we use reflect instead of unsafe to implement
+// the same (but slower) interface.
+type pointer struct {
+ p unsafe.Pointer
+}
+
+// size of pointer
+var ptrSize = unsafe.Sizeof(uintptr(0))
+
+// toPointer converts an interface of pointer type to a pointer
+// that points to the same target.
+func toPointer(i *Message) pointer {
+ // Super-tricky - read pointer out of data word of interface value.
+ // Saves ~25ns over the equivalent:
+ // return valToPointer(reflect.ValueOf(*i))
+ return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]}
+}
+
+// toAddrPointer converts an interface to a pointer that points to
+// the interface data.
+func toAddrPointer(i *interface{}, isptr, deref bool) (p pointer) {
+ // Super-tricky - read or get the address of data word of interface value.
+ if isptr {
+ // The interface is of pointer type, thus it is a direct interface.
+ // The data word is the pointer data itself. We take its address.
+ p = pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)}
+ } else {
+ // The interface is not of pointer type. The data word is the pointer
+ // to the data.
+ p = pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]}
+ }
+ if deref {
+ p.p = *(*unsafe.Pointer)(p.p)
+ }
+ return p
}
-// Bytes returns the address of a []byte field in the struct.
-func structPointer_Bytes(p structPointer, f field) *[]byte {
- return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+// valToPointer converts v to a pointer. v must be of pointer type.
+func valToPointer(v reflect.Value) pointer {
+ return pointer{p: unsafe.Pointer(v.Pointer())}
}
-// BytesSlice returns the address of a [][]byte field in the struct.
-func structPointer_BytesSlice(p structPointer, f field) *[][]byte {
- return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+// offset converts from a pointer to a structure to a pointer to
+// one of its fields.
+func (p pointer) offset(f field) pointer {
+ // For safety, we should panic if !f.IsValid, however calling panic causes
+ // this to no longer be inlineable, which is a serious performance cost.
+ /*
+ if !f.IsValid() {
+ panic("invalid field")
+ }
+ */
+ return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))}
}
-// Bool returns the address of a *bool field in the struct.
-func structPointer_Bool(p structPointer, f field) **bool {
- return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+func (p pointer) isNil() bool {
+ return p.p == nil
}
-// BoolVal returns the address of a bool field in the struct.
-func structPointer_BoolVal(p structPointer, f field) *bool {
- return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+func (p pointer) toInt64() *int64 {
+ return (*int64)(p.p)
}
-
-// BoolSlice returns the address of a []bool field in the struct.
-func structPointer_BoolSlice(p structPointer, f field) *[]bool {
- return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+func (p pointer) toInt64Ptr() **int64 {
+ return (**int64)(p.p)
}
-
-// String returns the address of a *string field in the struct.
-func structPointer_String(p structPointer, f field) **string {
- return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+func (p pointer) toInt64Slice() *[]int64 {
+ return (*[]int64)(p.p)
}
-
-// StringVal returns the address of a string field in the struct.
-func structPointer_StringVal(p structPointer, f field) *string {
- return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+func (p pointer) toInt32() *int32 {
+ return (*int32)(p.p)
}
-// StringSlice returns the address of a []string field in the struct.
-func structPointer_StringSlice(p structPointer, f field) *[]string {
- return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+// See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist.
+/*
+ func (p pointer) toInt32Ptr() **int32 {
+ return (**int32)(p.p)
+ }
+ func (p pointer) toInt32Slice() *[]int32 {
+ return (*[]int32)(p.p)
+ }
+*/
+func (p pointer) getInt32Ptr() *int32 {
+ return *(**int32)(p.p)
}
-
-// ExtMap returns the address of an extension map field in the struct.
-func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions {
- return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+func (p pointer) setInt32Ptr(v int32) {
+ *(**int32)(p.p) = &v
}
-func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
- return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+// getInt32Slice loads a []int32 from p.
+// The value returned is aliased with the original slice.
+// This behavior differs from the implementation in pointer_reflect.go.
+func (p pointer) getInt32Slice() []int32 {
+ return *(*[]int32)(p.p)
}
-// NewAt returns the reflect.Value for a pointer to a field in the struct.
-func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value {
- return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f)))
+// setInt32Slice stores a []int32 to p.
+// The value set is aliased with the input slice.
+// This behavior differs from the implementation in pointer_reflect.go.
+func (p pointer) setInt32Slice(v []int32) {
+ *(*[]int32)(p.p) = v
}
-// SetStructPointer writes a *struct field in the struct.
-func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
- *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q
+// TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead?
+func (p pointer) appendInt32Slice(v int32) {
+ s := (*[]int32)(p.p)
+ *s = append(*s, v)
}
-// GetStructPointer reads a *struct field in the struct.
-func structPointer_GetStructPointer(p structPointer, f field) structPointer {
- return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+func (p pointer) toUint64() *uint64 {
+ return (*uint64)(p.p)
}
-
-// StructPointerSlice the address of a []*struct field in the struct.
-func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice {
- return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+func (p pointer) toUint64Ptr() **uint64 {
+ return (**uint64)(p.p)
}
-
-// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups).
-type structPointerSlice []structPointer
-
-func (v *structPointerSlice) Len() int { return len(*v) }
-func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] }
-func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) }
-
-// A word32 is the address of a "pointer to 32-bit value" field.
-type word32 **uint32
-
-// IsNil reports whether *v is nil.
-func word32_IsNil(p word32) bool {
- return *p == nil
+func (p pointer) toUint64Slice() *[]uint64 {
+ return (*[]uint64)(p.p)
}
-
-// Set sets *v to point at a newly allocated word set to x.
-func word32_Set(p word32, o *Buffer, x uint32) {
- if len(o.uint32s) == 0 {
- o.uint32s = make([]uint32, uint32PoolSize)
- }
- o.uint32s[0] = x
- *p = &o.uint32s[0]
- o.uint32s = o.uint32s[1:]
+func (p pointer) toUint32() *uint32 {
+ return (*uint32)(p.p)
}
-
-// Get gets the value pointed at by *v.
-func word32_Get(p word32) uint32 {
- return **p
+func (p pointer) toUint32Ptr() **uint32 {
+ return (**uint32)(p.p)
}
-
-// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct.
-func structPointer_Word32(p structPointer, f field) word32 {
- return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f))))
+func (p pointer) toUint32Slice() *[]uint32 {
+ return (*[]uint32)(p.p)
}
-
-// A word32Val is the address of a 32-bit value field.
-type word32Val *uint32
-
-// Set sets *p to x.
-func word32Val_Set(p word32Val, x uint32) {
- *p = x
+func (p pointer) toBool() *bool {
+ return (*bool)(p.p)
}
-
-// Get gets the value pointed at by p.
-func word32Val_Get(p word32Val) uint32 {
- return *p
+func (p pointer) toBoolPtr() **bool {
+ return (**bool)(p.p)
}
-
-// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct.
-func structPointer_Word32Val(p structPointer, f field) word32Val {
- return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f))))
+func (p pointer) toBoolSlice() *[]bool {
+ return (*[]bool)(p.p)
}
-
-// A word32Slice is a slice of 32-bit values.
-type word32Slice []uint32
-
-func (v *word32Slice) Append(x uint32) { *v = append(*v, x) }
-func (v *word32Slice) Len() int { return len(*v) }
-func (v *word32Slice) Index(i int) uint32 { return (*v)[i] }
-
-// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct.
-func structPointer_Word32Slice(p structPointer, f field) *word32Slice {
- return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+func (p pointer) toFloat64() *float64 {
+ return (*float64)(p.p)
}
-
-// word64 is like word32 but for 64-bit values.
-type word64 **uint64
-
-func word64_Set(p word64, o *Buffer, x uint64) {
- if len(o.uint64s) == 0 {
- o.uint64s = make([]uint64, uint64PoolSize)
- }
- o.uint64s[0] = x
- *p = &o.uint64s[0]
- o.uint64s = o.uint64s[1:]
+func (p pointer) toFloat64Ptr() **float64 {
+ return (**float64)(p.p)
}
-
-func word64_IsNil(p word64) bool {
- return *p == nil
+func (p pointer) toFloat64Slice() *[]float64 {
+ return (*[]float64)(p.p)
}
-
-func word64_Get(p word64) uint64 {
- return **p
+func (p pointer) toFloat32() *float32 {
+ return (*float32)(p.p)
+}
+func (p pointer) toFloat32Ptr() **float32 {
+ return (**float32)(p.p)
+}
+func (p pointer) toFloat32Slice() *[]float32 {
+ return (*[]float32)(p.p)
+}
+func (p pointer) toString() *string {
+ return (*string)(p.p)
+}
+func (p pointer) toStringPtr() **string {
+ return (**string)(p.p)
+}
+func (p pointer) toStringSlice() *[]string {
+ return (*[]string)(p.p)
+}
+func (p pointer) toBytes() *[]byte {
+ return (*[]byte)(p.p)
+}
+func (p pointer) toBytesSlice() *[][]byte {
+ return (*[][]byte)(p.p)
+}
+func (p pointer) toExtensions() *XXX_InternalExtensions {
+ return (*XXX_InternalExtensions)(p.p)
+}
+func (p pointer) toOldExtensions() *map[int32]Extension {
+ return (*map[int32]Extension)(p.p)
}
-func structPointer_Word64(p structPointer, f field) word64 {
- return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f))))
+// getPointerSlice loads []*T from p as a []pointer.
+// The value returned is aliased with the original slice.
+// This behavior differs from the implementation in pointer_reflect.go.
+func (p pointer) getPointerSlice() []pointer {
+ // Super-tricky - p should point to a []*T where T is a
+ // message type. We load it as []pointer.
+ return *(*[]pointer)(p.p)
}
-// word64Val is like word32Val but for 64-bit values.
-type word64Val *uint64
+// setPointerSlice stores []pointer into p as a []*T.
+// The value set is aliased with the input slice.
+// This behavior differs from the implementation in pointer_reflect.go.
+func (p pointer) setPointerSlice(v []pointer) {
+ // Super-tricky - p should point to a []*T where T is a
+ // message type. We store it as []pointer.
+ *(*[]pointer)(p.p) = v
+}
-func word64Val_Set(p word64Val, o *Buffer, x uint64) {
- *p = x
+// getPointer loads the pointer at p and returns it.
+func (p pointer) getPointer() pointer {
+ return pointer{p: *(*unsafe.Pointer)(p.p)}
}
-func word64Val_Get(p word64Val) uint64 {
- return *p
+// setPointer stores the pointer q at p.
+func (p pointer) setPointer(q pointer) {
+ *(*unsafe.Pointer)(p.p) = q.p
}
-func structPointer_Word64Val(p structPointer, f field) word64Val {
- return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f))))
+// append q to the slice pointed to by p.
+func (p pointer) appendPointer(q pointer) {
+ s := (*[]unsafe.Pointer)(p.p)
+ *s = append(*s, q.p)
}
-// word64Slice is like word32Slice but for 64-bit values.
-type word64Slice []uint64
+// getInterfacePointer returns a pointer that points to the
+// interface data of the interface pointed by p.
+func (p pointer) getInterfacePointer() pointer {
+ // Super-tricky - read pointer out of data word of interface value.
+ return pointer{p: (*(*[2]unsafe.Pointer)(p.p))[1]}
+}
-func (v *word64Slice) Append(x uint64) { *v = append(*v, x) }
-func (v *word64Slice) Len() int { return len(*v) }
-func (v *word64Slice) Index(i int) uint64 { return (*v)[i] }
+// asPointerTo returns a reflect.Value that is a pointer to an
+// object of type t stored at p.
+func (p pointer) asPointerTo(t reflect.Type) reflect.Value {
+ return reflect.NewAt(t, p.p)
+}
-func structPointer_Word64Slice(p structPointer, f field) *word64Slice {
- return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
+func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo {
+ return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
+}
+func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) {
+ atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
+}
+func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo {
+ return (*marshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
+}
+func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) {
+ atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
+}
+func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo {
+ return (*mergeInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
+}
+func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) {
+ atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
+}
+func atomicLoadDiscardInfo(p **discardInfo) *discardInfo {
+ return (*discardInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
+}
+func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) {
+ atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
}
diff --git a/vendor/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/golang/protobuf/proto/properties.go
index ec2289c00..a4b8c0cd3 100644
--- a/vendor/github.com/golang/protobuf/proto/properties.go
+++ b/vendor/github.com/golang/protobuf/proto/properties.go
@@ -38,7 +38,6 @@ package proto
import (
"fmt"
"log"
- "os"
"reflect"
"sort"
"strconv"
@@ -58,42 +57,6 @@ const (
WireFixed32 = 5
)
-const startSize = 10 // initial slice/string sizes
-
-// Encoders are defined in encode.go
-// An encoder outputs the full representation of a field, including its
-// tag and encoder type.
-type encoder func(p *Buffer, prop *Properties, base structPointer) error
-
-// A valueEncoder encodes a single integer in a particular encoding.
-type valueEncoder func(o *Buffer, x uint64) error
-
-// Sizers are defined in encode.go
-// A sizer returns the encoded size of a field, including its tag and encoder
-// type.
-type sizer func(prop *Properties, base structPointer) int
-
-// A valueSizer returns the encoded size of a single integer in a particular
-// encoding.
-type valueSizer func(x uint64) int
-
-// Decoders are defined in decode.go
-// A decoder creates a value from its wire representation.
-// Unrecognized subelements are saved in unrec.
-type decoder func(p *Buffer, prop *Properties, base structPointer) error
-
-// A valueDecoder decodes a single integer in a particular encoding.
-type valueDecoder func(o *Buffer) (x uint64, err error)
-
-// A oneofMarshaler does the marshaling for all oneof fields in a message.
-type oneofMarshaler func(Message, *Buffer) error
-
-// A oneofUnmarshaler does the unmarshaling for a oneof field in a message.
-type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error)
-
-// A oneofSizer does the sizing for all oneof fields in a message.
-type oneofSizer func(Message) int
-
// tagMap is an optimization over map[int]int for typical protocol buffer
// use-cases. Encoded protocol buffers are often in tag order with small tag
// numbers.
@@ -140,13 +103,6 @@ type StructProperties struct {
decoderTags tagMap // map from proto tag to struct field number
decoderOrigNames map[string]int // map from original name to struct field number
order []int // list of struct field numbers in tag order
- unrecField field // field id of the XXX_unrecognized []byte field
- extendable bool // is this an extendable proto
-
- oneofMarshaler oneofMarshaler
- oneofUnmarshaler oneofUnmarshaler
- oneofSizer oneofSizer
- stype reflect.Type
// OneofTypes contains information about the oneof fields in this message.
// It is keyed by the original name of a field.
@@ -182,41 +138,24 @@ type Properties struct {
Repeated bool
Packed bool // relevant for repeated primitives only
Enum string // set for enum types only
- proto3 bool // whether this is known to be a proto3 field; set for []byte only
+ proto3 bool // whether this is known to be a proto3 field
oneof bool // whether this is a oneof field
Default string // default value
HasDefault bool // whether an explicit default was provided
- def_uint64 uint64
-
- enc encoder
- valEnc valueEncoder // set for bool and numeric types only
- field field
- tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
- tagbuf [8]byte
- stype reflect.Type // set for struct types only
- sprop *StructProperties // set for struct types only
- isMarshaler bool
- isUnmarshaler bool
-
- mtype reflect.Type // set for map types only
- mkeyprop *Properties // set for map types only
- mvalprop *Properties // set for map types only
-
- size sizer
- valSize valueSizer // set for bool and numeric types only
-
- dec decoder
- valDec valueDecoder // set for bool and numeric types only
-
- // If this is a packable field, this will be the decoder for the packed version of the field.
- packedDec decoder
+
+ stype reflect.Type // set for struct types only
+ sprop *StructProperties // set for struct types only
+
+ mtype reflect.Type // set for map types only
+ MapKeyProp *Properties // set for map types only
+ MapValProp *Properties // set for map types only
}
// String formats the properties in the protobuf struct field tag style.
func (p *Properties) String() string {
s := p.Wire
- s = ","
+ s += ","
s += strconv.Itoa(p.Tag)
if p.Required {
s += ",req"
@@ -254,7 +193,7 @@ func (p *Properties) Parse(s string) {
// "bytes,49,opt,name=foo,def=hello!"
fields := strings.Split(s, ",") // breaks def=, but handled below.
if len(fields) < 2 {
- fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
+ log.Printf("proto: tag has too few fields: %q", s)
return
}
@@ -262,34 +201,19 @@ func (p *Properties) Parse(s string) {
switch p.Wire {
case "varint":
p.WireType = WireVarint
- p.valEnc = (*Buffer).EncodeVarint
- p.valDec = (*Buffer).DecodeVarint
- p.valSize = sizeVarint
case "fixed32":
p.WireType = WireFixed32
- p.valEnc = (*Buffer).EncodeFixed32
- p.valDec = (*Buffer).DecodeFixed32
- p.valSize = sizeFixed32
case "fixed64":
p.WireType = WireFixed64
- p.valEnc = (*Buffer).EncodeFixed64
- p.valDec = (*Buffer).DecodeFixed64
- p.valSize = sizeFixed64
case "zigzag32":
p.WireType = WireVarint
- p.valEnc = (*Buffer).EncodeZigzag32
- p.valDec = (*Buffer).DecodeZigzag32
- p.valSize = sizeZigzag32
case "zigzag64":
p.WireType = WireVarint
- p.valEnc = (*Buffer).EncodeZigzag64
- p.valDec = (*Buffer).DecodeZigzag64
- p.valSize = sizeZigzag64
case "bytes", "group":
p.WireType = WireBytes
// no numeric converter for non-numeric types
default:
- fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
+ log.Printf("proto: tag has unknown wire type: %q", s)
return
}
@@ -299,6 +223,7 @@ func (p *Properties) Parse(s string) {
return
}
+outer:
for i := 2; i < len(fields); i++ {
f := fields[i]
switch {
@@ -326,255 +251,40 @@ func (p *Properties) Parse(s string) {
if i+1 < len(fields) {
// Commas aren't escaped, and def is always last.
p.Default += "," + strings.Join(fields[i+1:], ",")
- break
+ break outer
}
}
}
}
-func logNoSliceEnc(t1, t2 reflect.Type) {
- fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
-}
-
var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
-// Initialize the fields for encoding and decoding.
-func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) {
- p.enc = nil
- p.dec = nil
- p.size = nil
-
+// setFieldProps initializes the field properties for submessages and maps.
+func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) {
switch t1 := typ; t1.Kind() {
- default:
- fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1)
-
- // proto3 scalar types
-
- case reflect.Bool:
- p.enc = (*Buffer).enc_proto3_bool
- p.dec = (*Buffer).dec_proto3_bool
- p.size = size_proto3_bool
- case reflect.Int32:
- p.enc = (*Buffer).enc_proto3_int32
- p.dec = (*Buffer).dec_proto3_int32
- p.size = size_proto3_int32
- case reflect.Uint32:
- p.enc = (*Buffer).enc_proto3_uint32
- p.dec = (*Buffer).dec_proto3_int32 // can reuse
- p.size = size_proto3_uint32
- case reflect.Int64, reflect.Uint64:
- p.enc = (*Buffer).enc_proto3_int64
- p.dec = (*Buffer).dec_proto3_int64
- p.size = size_proto3_int64
- case reflect.Float32:
- p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits
- p.dec = (*Buffer).dec_proto3_int32
- p.size = size_proto3_uint32
- case reflect.Float64:
- p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits
- p.dec = (*Buffer).dec_proto3_int64
- p.size = size_proto3_int64
- case reflect.String:
- p.enc = (*Buffer).enc_proto3_string
- p.dec = (*Buffer).dec_proto3_string
- p.size = size_proto3_string
-
case reflect.Ptr:
- switch t2 := t1.Elem(); t2.Kind() {
- default:
- fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2)
- break
- case reflect.Bool:
- p.enc = (*Buffer).enc_bool
- p.dec = (*Buffer).dec_bool
- p.size = size_bool
- case reflect.Int32:
- p.enc = (*Buffer).enc_int32
- p.dec = (*Buffer).dec_int32
- p.size = size_int32
- case reflect.Uint32:
- p.enc = (*Buffer).enc_uint32
- p.dec = (*Buffer).dec_int32 // can reuse
- p.size = size_uint32
- case reflect.Int64, reflect.Uint64:
- p.enc = (*Buffer).enc_int64
- p.dec = (*Buffer).dec_int64
- p.size = size_int64
- case reflect.Float32:
- p.enc = (*Buffer).enc_uint32 // can just treat them as bits
- p.dec = (*Buffer).dec_int32
- p.size = size_uint32
- case reflect.Float64:
- p.enc = (*Buffer).enc_int64 // can just treat them as bits
- p.dec = (*Buffer).dec_int64
- p.size = size_int64
- case reflect.String:
- p.enc = (*Buffer).enc_string
- p.dec = (*Buffer).dec_string
- p.size = size_string
- case reflect.Struct:
+ if t1.Elem().Kind() == reflect.Struct {
p.stype = t1.Elem()
- p.isMarshaler = isMarshaler(t1)
- p.isUnmarshaler = isUnmarshaler(t1)
- if p.Wire == "bytes" {
- p.enc = (*Buffer).enc_struct_message
- p.dec = (*Buffer).dec_struct_message
- p.size = size_struct_message
- } else {
- p.enc = (*Buffer).enc_struct_group
- p.dec = (*Buffer).dec_struct_group
- p.size = size_struct_group
- }
}
case reflect.Slice:
- switch t2 := t1.Elem(); t2.Kind() {
- default:
- logNoSliceEnc(t1, t2)
- break
- case reflect.Bool:
- if p.Packed {
- p.enc = (*Buffer).enc_slice_packed_bool
- p.size = size_slice_packed_bool
- } else {
- p.enc = (*Buffer).enc_slice_bool
- p.size = size_slice_bool
- }
- p.dec = (*Buffer).dec_slice_bool
- p.packedDec = (*Buffer).dec_slice_packed_bool
- case reflect.Int32:
- if p.Packed {
- p.enc = (*Buffer).enc_slice_packed_int32
- p.size = size_slice_packed_int32
- } else {
- p.enc = (*Buffer).enc_slice_int32
- p.size = size_slice_int32
- }
- p.dec = (*Buffer).dec_slice_int32
- p.packedDec = (*Buffer).dec_slice_packed_int32
- case reflect.Uint32:
- if p.Packed {
- p.enc = (*Buffer).enc_slice_packed_uint32
- p.size = size_slice_packed_uint32
- } else {
- p.enc = (*Buffer).enc_slice_uint32
- p.size = size_slice_uint32
- }
- p.dec = (*Buffer).dec_slice_int32
- p.packedDec = (*Buffer).dec_slice_packed_int32
- case reflect.Int64, reflect.Uint64:
- if p.Packed {
- p.enc = (*Buffer).enc_slice_packed_int64
- p.size = size_slice_packed_int64
- } else {
- p.enc = (*Buffer).enc_slice_int64
- p.size = size_slice_int64
- }
- p.dec = (*Buffer).dec_slice_int64
- p.packedDec = (*Buffer).dec_slice_packed_int64
- case reflect.Uint8:
- p.dec = (*Buffer).dec_slice_byte
- if p.proto3 {
- p.enc = (*Buffer).enc_proto3_slice_byte
- p.size = size_proto3_slice_byte
- } else {
- p.enc = (*Buffer).enc_slice_byte
- p.size = size_slice_byte
- }
- case reflect.Float32, reflect.Float64:
- switch t2.Bits() {
- case 32:
- // can just treat them as bits
- if p.Packed {
- p.enc = (*Buffer).enc_slice_packed_uint32
- p.size = size_slice_packed_uint32
- } else {
- p.enc = (*Buffer).enc_slice_uint32
- p.size = size_slice_uint32
- }
- p.dec = (*Buffer).dec_slice_int32
- p.packedDec = (*Buffer).dec_slice_packed_int32
- case 64:
- // can just treat them as bits
- if p.Packed {
- p.enc = (*Buffer).enc_slice_packed_int64
- p.size = size_slice_packed_int64
- } else {
- p.enc = (*Buffer).enc_slice_int64
- p.size = size_slice_int64
- }
- p.dec = (*Buffer).dec_slice_int64
- p.packedDec = (*Buffer).dec_slice_packed_int64
- default:
- logNoSliceEnc(t1, t2)
- break
- }
- case reflect.String:
- p.enc = (*Buffer).enc_slice_string
- p.dec = (*Buffer).dec_slice_string
- p.size = size_slice_string
- case reflect.Ptr:
- switch t3 := t2.Elem(); t3.Kind() {
- default:
- fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
- break
- case reflect.Struct:
- p.stype = t2.Elem()
- p.isMarshaler = isMarshaler(t2)
- p.isUnmarshaler = isUnmarshaler(t2)
- if p.Wire == "bytes" {
- p.enc = (*Buffer).enc_slice_struct_message
- p.dec = (*Buffer).dec_slice_struct_message
- p.size = size_slice_struct_message
- } else {
- p.enc = (*Buffer).enc_slice_struct_group
- p.dec = (*Buffer).dec_slice_struct_group
- p.size = size_slice_struct_group
- }
- }
- case reflect.Slice:
- switch t2.Elem().Kind() {
- default:
- fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem())
- break
- case reflect.Uint8:
- p.enc = (*Buffer).enc_slice_slice_byte
- p.dec = (*Buffer).dec_slice_slice_byte
- p.size = size_slice_slice_byte
- }
+ if t2 := t1.Elem(); t2.Kind() == reflect.Ptr && t2.Elem().Kind() == reflect.Struct {
+ p.stype = t2.Elem()
}
case reflect.Map:
- p.enc = (*Buffer).enc_new_map
- p.dec = (*Buffer).dec_new_map
- p.size = size_new_map
-
p.mtype = t1
- p.mkeyprop = &Properties{}
- p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
- p.mvalprop = &Properties{}
+ p.MapKeyProp = &Properties{}
+ p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
+ p.MapValProp = &Properties{}
vtype := p.mtype.Elem()
if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
// The value type is not a message (*T) or bytes ([]byte),
// so we need encoders for the pointer to this type.
vtype = reflect.PtrTo(vtype)
}
- p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
- }
-
- // precalculate tag code
- wire := p.WireType
- if p.Packed {
- wire = WireBytes
+ p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
}
- x := uint32(p.Tag)<<3 | uint32(wire)
- i := 0
- for i = 0; x > 127; i++ {
- p.tagbuf[i] = 0x80 | uint8(x&0x7F)
- x >>= 7
- }
- p.tagbuf[i] = uint8(x)
- p.tagcode = p.tagbuf[0 : i+1]
if p.stype != nil {
if lockGetProp {
@@ -586,32 +296,9 @@ func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lock
}
var (
- marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
- unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
+ marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
)
-// isMarshaler reports whether type t implements Marshaler.
-func isMarshaler(t reflect.Type) bool {
- // We're checking for (likely) pointer-receiver methods
- // so if t is not a pointer, something is very wrong.
- // The calls above only invoke isMarshaler on pointer types.
- if t.Kind() != reflect.Ptr {
- panic("proto: misuse of isMarshaler")
- }
- return t.Implements(marshalerType)
-}
-
-// isUnmarshaler reports whether type t implements Unmarshaler.
-func isUnmarshaler(t reflect.Type) bool {
- // We're checking for (likely) pointer-receiver methods
- // so if t is not a pointer, something is very wrong.
- // The calls above only invoke isUnmarshaler on pointer types.
- if t.Kind() != reflect.Ptr {
- panic("proto: misuse of isUnmarshaler")
- }
- return t.Implements(unmarshalerType)
-}
-
// Init populates the properties from a protocol buffer struct tag.
func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
p.init(typ, name, tag, f, true)
@@ -621,14 +308,11 @@ func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructF
// "bytes,49,opt,def=hello!"
p.Name = name
p.OrigName = name
- if f != nil {
- p.field = toField(f)
- }
if tag == "" {
return
}
p.Parse(tag)
- p.setEncAndDec(typ, f, lockGetProp)
+ p.setFieldProps(typ, f, lockGetProp)
}
var (
@@ -649,9 +333,6 @@ func GetProperties(t reflect.Type) *StructProperties {
sprop, ok := propertiesMap[t]
propertiesMu.RUnlock()
if ok {
- if collectStats {
- stats.Chit++
- }
return sprop
}
@@ -661,26 +342,26 @@ func GetProperties(t reflect.Type) *StructProperties {
return sprop
}
+type (
+ oneofFuncsIface interface {
+ XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
+ }
+ oneofWrappersIface interface {
+ XXX_OneofWrappers() []interface{}
+ }
+)
+
// getPropertiesLocked requires that propertiesMu is held.
func getPropertiesLocked(t reflect.Type) *StructProperties {
if prop, ok := propertiesMap[t]; ok {
- if collectStats {
- stats.Chit++
- }
return prop
}
- if collectStats {
- stats.Cmiss++
- }
prop := new(StructProperties)
// in case of recursive protos, fill this in now.
propertiesMap[t] = prop
// build properties
- prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) ||
- reflect.PtrTo(t).Implements(extendableProtoV1Type)
- prop.unrecField = invalidField
prop.Prop = make([]*Properties, t.NumField())
prop.order = make([]int, t.NumField())
@@ -690,17 +371,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
name := f.Name
p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
- if f.Name == "XXX_InternalExtensions" { // special case
- p.enc = (*Buffer).enc_exts
- p.dec = nil // not needed
- p.size = size_exts
- } else if f.Name == "XXX_extensions" { // special case
- p.enc = (*Buffer).enc_map
- p.dec = nil // not needed
- p.size = size_map
- } else if f.Name == "XXX_unrecognized" { // special case
- prop.unrecField = toField(&f)
- }
oneof := f.Tag.Get("protobuf_oneof") // special case
if oneof != "" {
// Oneof fields don't use the traditional protobuf tag.
@@ -715,22 +385,19 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
}
print("\n")
}
- if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" {
- fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
- }
}
// Re-order prop.order.
sort.Sort(prop)
- type oneofMessage interface {
- XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
+ var oots []interface{}
+ switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) {
+ case oneofFuncsIface:
+ _, _, _, oots = m.XXX_OneofFuncs()
+ case oneofWrappersIface:
+ oots = m.XXX_OneofWrappers()
}
- if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
- var oots []interface{}
- prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs()
- prop.stype = t
-
+ if len(oots) > 0 {
// Interpret oneof metadata.
prop.OneofTypes = make(map[string]*OneofProperties)
for _, oot := range oots {
@@ -779,30 +446,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
return prop
}
-// Return the Properties object for the x[0]'th field of the structure.
-func propByIndex(t reflect.Type, x []int) *Properties {
- if len(x) != 1 {
- fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
- return nil
- }
- prop := GetProperties(t)
- return prop.Prop[x[0]]
-}
-
-// Get the address and type of a pointer to a struct from an interface.
-func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
- if pb == nil {
- err = ErrNil
- return
- }
- // get the reflect type of the pointer to the struct.
- t = reflect.TypeOf(pb)
- // get the address of the struct.
- value := reflect.ValueOf(pb)
- b = toStructPointer(value)
- return
-}
-
// A global registry of enum types.
// The generated code will register the generated maps by calling RegisterEnum.
@@ -826,20 +469,42 @@ func EnumValueMap(enumType string) map[string]int32 {
// A registry of all linked message types.
// The string is a fully-qualified proto name ("pkg.Message").
var (
- protoTypes = make(map[string]reflect.Type)
- revProtoTypes = make(map[reflect.Type]string)
+ protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers
+ protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types
+ revProtoTypes = make(map[reflect.Type]string)
)
// RegisterType is called from generated code and maps from the fully qualified
// proto name to the type (pointer to struct) of the protocol buffer.
func RegisterType(x Message, name string) {
- if _, ok := protoTypes[name]; ok {
+ if _, ok := protoTypedNils[name]; ok {
// TODO: Some day, make this a panic.
log.Printf("proto: duplicate proto type registered: %s", name)
return
}
t := reflect.TypeOf(x)
- protoTypes[name] = t
+ if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 {
+ // Generated code always calls RegisterType with nil x.
+ // This check is just for extra safety.
+ protoTypedNils[name] = x
+ } else {
+ protoTypedNils[name] = reflect.Zero(t).Interface().(Message)
+ }
+ revProtoTypes[t] = name
+}
+
+// RegisterMapType is called from generated code and maps from the fully qualified
+// proto name to the native map type of the proto map definition.
+func RegisterMapType(x interface{}, name string) {
+ if reflect.TypeOf(x).Kind() != reflect.Map {
+ panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name))
+ }
+ if _, ok := protoMapTypes[name]; ok {
+ log.Printf("proto: duplicate proto type registered: %s", name)
+ return
+ }
+ t := reflect.TypeOf(x)
+ protoMapTypes[name] = t
revProtoTypes[t] = name
}
@@ -855,7 +520,14 @@ func MessageName(x Message) string {
}
// MessageType returns the message type (pointer to struct) for a named message.
-func MessageType(name string) reflect.Type { return protoTypes[name] }
+// The type is not guaranteed to implement proto.Message if the name refers to a
+// map entry.
+func MessageType(name string) reflect.Type {
+ if t, ok := protoTypedNils[name]; ok {
+ return reflect.TypeOf(t)
+ }
+ return protoMapTypes[name]
+}
// A registry of all linked proto files.
var (
diff --git a/vendor/github.com/golang/protobuf/proto/table_marshal.go b/vendor/github.com/golang/protobuf/proto/table_marshal.go
new file mode 100644
index 000000000..5cb11fa95
--- /dev/null
+++ b/vendor/github.com/golang/protobuf/proto/table_marshal.go
@@ -0,0 +1,2776 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2016 The Go Authors. All rights reserved.
+// https://github.com/golang/protobuf
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto
+
+import (
+ "errors"
+ "fmt"
+ "math"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "unicode/utf8"
+)
+
+// a sizer takes a pointer to a field and the size of its tag, computes the size of
+// the encoded data.
+type sizer func(pointer, int) int
+
+// a marshaler takes a byte slice, a pointer to a field, and its tag (in wire format),
+// marshals the field to the end of the slice, returns the slice and error (if any).
+type marshaler func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error)
+
+// marshalInfo is the information used for marshaling a message.
+type marshalInfo struct {
+ typ reflect.Type
+ fields []*marshalFieldInfo
+ unrecognized field // offset of XXX_unrecognized
+ extensions field // offset of XXX_InternalExtensions
+ v1extensions field // offset of XXX_extensions
+ sizecache field // offset of XXX_sizecache
+ initialized int32 // 0 -- only typ is set, 1 -- fully initialized
+ messageset bool // uses message set wire format
+ hasmarshaler bool // has custom marshaler
+ sync.RWMutex // protect extElems map, also for initialization
+ extElems map[int32]*marshalElemInfo // info of extension elements
+}
+
+// marshalFieldInfo is the information used for marshaling a field of a message.
+type marshalFieldInfo struct {
+ field field
+ wiretag uint64 // tag in wire format
+ tagsize int // size of tag in wire format
+ sizer sizer
+ marshaler marshaler
+ isPointer bool
+ required bool // field is required
+ name string // name of the field, for error reporting
+ oneofElems map[reflect.Type]*marshalElemInfo // info of oneof elements
+}
+
+// marshalElemInfo is the information used for marshaling an extension or oneof element.
+type marshalElemInfo struct {
+ wiretag uint64 // tag in wire format
+ tagsize int // size of tag in wire format
+ sizer sizer
+ marshaler marshaler
+ isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only)
+ deref bool // dereference the pointer before operating on it; implies isptr
+}
+
+var (
+ marshalInfoMap = map[reflect.Type]*marshalInfo{}
+ marshalInfoLock sync.Mutex
+)
+
+// getMarshalInfo returns the information to marshal a given type of message.
+// The info it returns may not necessarily initialized.
+// t is the type of the message (NOT the pointer to it).
+func getMarshalInfo(t reflect.Type) *marshalInfo {
+ marshalInfoLock.Lock()
+ u, ok := marshalInfoMap[t]
+ if !ok {
+ u = &marshalInfo{typ: t}
+ marshalInfoMap[t] = u
+ }
+ marshalInfoLock.Unlock()
+ return u
+}
+
+// Size is the entry point from generated code,
+// and should be ONLY called by generated code.
+// It computes the size of encoded data of msg.
+// a is a pointer to a place to store cached marshal info.
+func (a *InternalMessageInfo) Size(msg Message) int {
+ u := getMessageMarshalInfo(msg, a)
+ ptr := toPointer(&msg)
+ if ptr.isNil() {
+ // We get here if msg is a typed nil ((*SomeMessage)(nil)),
+ // so it satisfies the interface, and msg == nil wouldn't
+ // catch it. We don't want crash in this case.
+ return 0
+ }
+ return u.size(ptr)
+}
+
+// Marshal is the entry point from generated code,
+// and should be ONLY called by generated code.
+// It marshals msg to the end of b.
+// a is a pointer to a place to store cached marshal info.
+func (a *InternalMessageInfo) Marshal(b []byte, msg Message, deterministic bool) ([]byte, error) {
+ u := getMessageMarshalInfo(msg, a)
+ ptr := toPointer(&msg)
+ if ptr.isNil() {
+ // We get here if msg is a typed nil ((*SomeMessage)(nil)),
+ // so it satisfies the interface, and msg == nil wouldn't
+ // catch it. We don't want crash in this case.
+ return b, ErrNil
+ }
+ return u.marshal(b, ptr, deterministic)
+}
+
+func getMessageMarshalInfo(msg interface{}, a *InternalMessageInfo) *marshalInfo {
+ // u := a.marshal, but atomically.
+ // We use an atomic here to ensure memory consistency.
+ u := atomicLoadMarshalInfo(&a.marshal)
+ if u == nil {
+ // Get marshal information from type of message.
+ t := reflect.ValueOf(msg).Type()
+ if t.Kind() != reflect.Ptr {
+ panic(fmt.Sprintf("cannot handle non-pointer message type %v", t))
+ }
+ u = getMarshalInfo(t.Elem())
+ // Store it in the cache for later users.
+ // a.marshal = u, but atomically.
+ atomicStoreMarshalInfo(&a.marshal, u)
+ }
+ return u
+}
+
+// size is the main function to compute the size of the encoded data of a message.
+// ptr is the pointer to the message.
+func (u *marshalInfo) size(ptr pointer) int {
+ if atomic.LoadInt32(&u.initialized) == 0 {
+ u.computeMarshalInfo()
+ }
+
+ // If the message can marshal itself, let it do it, for compatibility.
+ // NOTE: This is not efficient.
+ if u.hasmarshaler {
+ m := ptr.asPointerTo(u.typ).Interface().(Marshaler)
+ b, _ := m.Marshal()
+ return len(b)
+ }
+
+ n := 0
+ for _, f := range u.fields {
+ if f.isPointer && ptr.offset(f.field).getPointer().isNil() {
+ // nil pointer always marshals to nothing
+ continue
+ }
+ n += f.sizer(ptr.offset(f.field), f.tagsize)
+ }
+ if u.extensions.IsValid() {
+ e := ptr.offset(u.extensions).toExtensions()
+ if u.messageset {
+ n += u.sizeMessageSet(e)
+ } else {
+ n += u.sizeExtensions(e)
+ }
+ }
+ if u.v1extensions.IsValid() {
+ m := *ptr.offset(u.v1extensions).toOldExtensions()
+ n += u.sizeV1Extensions(m)
+ }
+ if u.unrecognized.IsValid() {
+ s := *ptr.offset(u.unrecognized).toBytes()
+ n += len(s)
+ }
+ // cache the result for use in marshal
+ if u.sizecache.IsValid() {
+ atomic.StoreInt32(ptr.offset(u.sizecache).toInt32(), int32(n))
+ }
+ return n
+}
+
+// cachedsize gets the size from cache. If there is no cache (i.e. message is not generated),
+// fall back to compute the size.
+func (u *marshalInfo) cachedsize(ptr pointer) int {
+ if u.sizecache.IsValid() {
+ return int(atomic.LoadInt32(ptr.offset(u.sizecache).toInt32()))
+ }
+ return u.size(ptr)
+}
+
+// marshal is the main function to marshal a message. It takes a byte slice and appends
+// the encoded data to the end of the slice, returns the slice and error (if any).
+// ptr is the pointer to the message.
+// If deterministic is true, map is marshaled in deterministic order.
+func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte, error) {
+ if atomic.LoadInt32(&u.initialized) == 0 {
+ u.computeMarshalInfo()
+ }
+
+ // If the message can marshal itself, let it do it, for compatibility.
+ // NOTE: This is not efficient.
+ if u.hasmarshaler {
+ m := ptr.asPointerTo(u.typ).Interface().(Marshaler)
+ b1, err := m.Marshal()
+ b = append(b, b1...)
+ return b, err
+ }
+
+ var err, errLater error
+ // The old marshaler encodes extensions at beginning.
+ if u.extensions.IsValid() {
+ e := ptr.offset(u.extensions).toExtensions()
+ if u.messageset {
+ b, err = u.appendMessageSet(b, e, deterministic)
+ } else {
+ b, err = u.appendExtensions(b, e, deterministic)
+ }
+ if err != nil {
+ return b, err
+ }
+ }
+ if u.v1extensions.IsValid() {
+ m := *ptr.offset(u.v1extensions).toOldExtensions()
+ b, err = u.appendV1Extensions(b, m, deterministic)
+ if err != nil {
+ return b, err
+ }
+ }
+ for _, f := range u.fields {
+ if f.required {
+ if ptr.offset(f.field).getPointer().isNil() {
+ // Required field is not set.
+ // We record the error but keep going, to give a complete marshaling.
+ if errLater == nil {
+ errLater = &RequiredNotSetError{f.name}
+ }
+ continue
+ }
+ }
+ if f.isPointer && ptr.offset(f.field).getPointer().isNil() {
+ // nil pointer always marshals to nothing
+ continue
+ }
+ b, err = f.marshaler(b, ptr.offset(f.field), f.wiretag, deterministic)
+ if err != nil {
+ if err1, ok := err.(*RequiredNotSetError); ok {
+ // Required field in submessage is not set.
+ // We record the error but keep going, to give a complete marshaling.
+ if errLater == nil {
+ errLater = &RequiredNotSetError{f.name + "." + err1.field}
+ }
+ continue
+ }
+ if err == errRepeatedHasNil {
+ err = errors.New("proto: repeated field " + f.name + " has nil element")
+ }
+ if err == errInvalidUTF8 {
+ if errLater == nil {
+ fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name
+ errLater = &invalidUTF8Error{fullName}
+ }
+ continue
+ }
+ return b, err
+ }
+ }
+ if u.unrecognized.IsValid() {
+ s := *ptr.offset(u.unrecognized).toBytes()
+ b = append(b, s...)
+ }
+ return b, errLater
+}
+
+// computeMarshalInfo initializes the marshal info.
+func (u *marshalInfo) computeMarshalInfo() {
+ u.Lock()
+ defer u.Unlock()
+ if u.initialized != 0 { // non-atomic read is ok as it is protected by the lock
+ return
+ }
+
+ t := u.typ
+ u.unrecognized = invalidField
+ u.extensions = invalidField
+ u.v1extensions = invalidField
+ u.sizecache = invalidField
+
+ // If the message can marshal itself, let it do it, for compatibility.
+ // NOTE: This is not efficient.
+ if reflect.PtrTo(t).Implements(marshalerType) {
+ u.hasmarshaler = true
+ atomic.StoreInt32(&u.initialized, 1)
+ return
+ }
+
+ // get oneof implementers
+ var oneofImplementers []interface{}
+ switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) {
+ case oneofFuncsIface:
+ _, _, _, oneofImplementers = m.XXX_OneofFuncs()
+ case oneofWrappersIface:
+ oneofImplementers = m.XXX_OneofWrappers()
+ }
+
+ n := t.NumField()
+
+ // deal with XXX fields first
+ for i := 0; i < t.NumField(); i++ {
+ f := t.Field(i)
+ if !strings.HasPrefix(f.Name, "XXX_") {
+ continue
+ }
+ switch f.Name {
+ case "XXX_sizecache":
+ u.sizecache = toField(&f)
+ case "XXX_unrecognized":
+ u.unrecognized = toField(&f)
+ case "XXX_InternalExtensions":
+ u.extensions = toField(&f)
+ u.messageset = f.Tag.Get("protobuf_messageset") == "1"
+ case "XXX_extensions":
+ u.v1extensions = toField(&f)
+ case "XXX_NoUnkeyedLiteral":
+ // nothing to do
+ default:
+ panic("unknown XXX field: " + f.Name)
+ }
+ n--
+ }
+
+ // normal fields
+ fields := make([]marshalFieldInfo, n) // batch allocation
+ u.fields = make([]*marshalFieldInfo, 0, n)
+ for i, j := 0, 0; i < t.NumField(); i++ {
+ f := t.Field(i)
+
+ if strings.HasPrefix(f.Name, "XXX_") {
+ continue
+ }
+ field := &fields[j]
+ j++
+ field.name = f.Name
+ u.fields = append(u.fields, field)
+ if f.Tag.Get("protobuf_oneof") != "" {
+ field.computeOneofFieldInfo(&f, oneofImplementers)
+ continue
+ }
+ if f.Tag.Get("protobuf") == "" {
+ // field has no tag (not in generated message), ignore it
+ u.fields = u.fields[:len(u.fields)-1]
+ j--
+ continue
+ }
+ field.computeMarshalFieldInfo(&f)
+ }
+
+ // fields are marshaled in tag order on the wire.
+ sort.Sort(byTag(u.fields))
+
+ atomic.StoreInt32(&u.initialized, 1)
+}
+
+// helper for sorting fields by tag
+type byTag []*marshalFieldInfo
+
+func (a byTag) Len() int { return len(a) }
+func (a byTag) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a byTag) Less(i, j int) bool { return a[i].wiretag < a[j].wiretag }
+
+// getExtElemInfo returns the information to marshal an extension element.
+// The info it returns is initialized.
+func (u *marshalInfo) getExtElemInfo(desc *ExtensionDesc) *marshalElemInfo {
+ // get from cache first
+ u.RLock()
+ e, ok := u.extElems[desc.Field]
+ u.RUnlock()
+ if ok {
+ return e
+ }
+
+ t := reflect.TypeOf(desc.ExtensionType) // pointer or slice to basic type or struct
+ tags := strings.Split(desc.Tag, ",")
+ tag, err := strconv.Atoi(tags[1])
+ if err != nil {
+ panic("tag is not an integer")
+ }
+ wt := wiretype(tags[0])
+ if t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct {
+ t = t.Elem()
+ }
+ sizer, marshaler := typeMarshaler(t, tags, false, false)
+ var deref bool
+ if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 {
+ t = reflect.PtrTo(t)
+ deref = true
+ }
+ e = &marshalElemInfo{
+ wiretag: uint64(tag)<<3 | wt,
+ tagsize: SizeVarint(uint64(tag) << 3),
+ sizer: sizer,
+ marshaler: marshaler,
+ isptr: t.Kind() == reflect.Ptr,
+ deref: deref,
+ }
+
+ // update cache
+ u.Lock()
+ if u.extElems == nil {
+ u.extElems = make(map[int32]*marshalElemInfo)
+ }
+ u.extElems[desc.Field] = e
+ u.Unlock()
+ return e
+}
+
+// computeMarshalFieldInfo fills up the information to marshal a field.
+func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) {
+ // parse protobuf tag of the field.
+ // tag has format of "bytes,49,opt,name=foo,def=hello!"
+ tags := strings.Split(f.Tag.Get("protobuf"), ",")
+ if tags[0] == "" {
+ return
+ }
+ tag, err := strconv.Atoi(tags[1])
+ if err != nil {
+ panic("tag is not an integer")
+ }
+ wt := wiretype(tags[0])
+ if tags[2] == "req" {
+ fi.required = true
+ }
+ fi.setTag(f, tag, wt)
+ fi.setMarshaler(f, tags)
+}
+
+func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) {
+ fi.field = toField(f)
+ fi.wiretag = math.MaxInt32 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire.
+ fi.isPointer = true
+ fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f)
+ fi.oneofElems = make(map[reflect.Type]*marshalElemInfo)
+
+ ityp := f.Type // interface type
+ for _, o := range oneofImplementers {
+ t := reflect.TypeOf(o)
+ if !t.Implements(ityp) {
+ continue
+ }
+ sf := t.Elem().Field(0) // oneof implementer is a struct with a single field
+ tags := strings.Split(sf.Tag.Get("protobuf"), ",")
+ tag, err := strconv.Atoi(tags[1])
+ if err != nil {
+ panic("tag is not an integer")
+ }
+ wt := wiretype(tags[0])
+ sizer, marshaler := typeMarshaler(sf.Type, tags, false, true) // oneof should not omit any zero value
+ fi.oneofElems[t.Elem()] = &marshalElemInfo{
+ wiretag: uint64(tag)<<3 | wt,
+ tagsize: SizeVarint(uint64(tag) << 3),
+ sizer: sizer,
+ marshaler: marshaler,
+ }
+ }
+}
+
+// wiretype returns the wire encoding of the type.
+func wiretype(encoding string) uint64 {
+ switch encoding {
+ case "fixed32":
+ return WireFixed32
+ case "fixed64":
+ return WireFixed64
+ case "varint", "zigzag32", "zigzag64":
+ return WireVarint
+ case "bytes":
+ return WireBytes
+ case "group":
+ return WireStartGroup
+ }
+ panic("unknown wire type " + encoding)
+}
+
+// setTag fills up the tag (in wire format) and its size in the info of a field.
+func (fi *marshalFieldInfo) setTag(f *reflect.StructField, tag int, wt uint64) {
+ fi.field = toField(f)
+ fi.wiretag = uint64(tag)<<3 | wt
+ fi.tagsize = SizeVarint(uint64(tag) << 3)
+}
+
+// setMarshaler fills up the sizer and marshaler in the info of a field.
+func (fi *marshalFieldInfo) setMarshaler(f *reflect.StructField, tags []string) {
+ switch f.Type.Kind() {
+ case reflect.Map:
+ // map field
+ fi.isPointer = true
+ fi.sizer, fi.marshaler = makeMapMarshaler(f)
+ return
+ case reflect.Ptr, reflect.Slice:
+ fi.isPointer = true
+ }
+ fi.sizer, fi.marshaler = typeMarshaler(f.Type, tags, true, false)
+}
+
+// typeMarshaler returns the sizer and marshaler of a given field.
+// t is the type of the field.
+// tags is the generated "protobuf" tag of the field.
+// If nozero is true, zero value is not marshaled to the wire.
+// If oneof is true, it is a oneof field.
+func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, marshaler) {
+ encoding := tags[0]
+
+ pointer := false
+ slice := false
+ if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 {
+ slice = true
+ t = t.Elem()
+ }
+ if t.Kind() == reflect.Ptr {
+ pointer = true
+ t = t.Elem()
+ }
+
+ packed := false
+ proto3 := false
+ validateUTF8 := true
+ for i := 2; i < len(tags); i++ {
+ if tags[i] == "packed" {
+ packed = true
+ }
+ if tags[i] == "proto3" {
+ proto3 = true
+ }
+ }
+ validateUTF8 = validateUTF8 && proto3
+
+ switch t.Kind() {
+ case reflect.Bool:
+ if pointer {
+ return sizeBoolPtr, appendBoolPtr
+ }
+ if slice {
+ if packed {
+ return sizeBoolPackedSlice, appendBoolPackedSlice
+ }
+ return sizeBoolSlice, appendBoolSlice
+ }
+ if nozero {
+ return sizeBoolValueNoZero, appendBoolValueNoZero
+ }
+ return sizeBoolValue, appendBoolValue
+ case reflect.Uint32:
+ switch encoding {
+ case "fixed32":
+ if pointer {
+ return sizeFixed32Ptr, appendFixed32Ptr
+ }
+ if slice {
+ if packed {
+ return sizeFixed32PackedSlice, appendFixed32PackedSlice
+ }
+ return sizeFixed32Slice, appendFixed32Slice
+ }
+ if nozero {
+ return sizeFixed32ValueNoZero, appendFixed32ValueNoZero
+ }
+ return sizeFixed32Value, appendFixed32Value
+ case "varint":
+ if pointer {
+ return sizeVarint32Ptr, appendVarint32Ptr
+ }
+ if slice {
+ if packed {
+ return sizeVarint32PackedSlice, appendVarint32PackedSlice
+ }
+ return sizeVarint32Slice, appendVarint32Slice
+ }
+ if nozero {
+ return sizeVarint32ValueNoZero, appendVarint32ValueNoZero
+ }
+ return sizeVarint32Value, appendVarint32Value
+ }
+ case reflect.Int32:
+ switch encoding {
+ case "fixed32":
+ if pointer {
+ return sizeFixedS32Ptr, appendFixedS32Ptr
+ }
+ if slice {
+ if packed {
+ return sizeFixedS32PackedSlice, appendFixedS32PackedSlice
+ }
+ return sizeFixedS32Slice, appendFixedS32Slice
+ }
+ if nozero {
+ return sizeFixedS32ValueNoZero, appendFixedS32ValueNoZero
+ }
+ return sizeFixedS32Value, appendFixedS32Value
+ case "varint":
+ if pointer {
+ return sizeVarintS32Ptr, appendVarintS32Ptr
+ }
+ if slice {
+ if packed {
+ return sizeVarintS32PackedSlice, appendVarintS32PackedSlice
+ }
+ return sizeVarintS32Slice, appendVarintS32Slice
+ }
+ if nozero {
+ return sizeVarintS32ValueNoZero, appendVarintS32ValueNoZero
+ }
+ return sizeVarintS32Value, appendVarintS32Value
+ case "zigzag32":
+ if pointer {
+ return sizeZigzag32Ptr, appendZigzag32Ptr
+ }
+ if slice {
+ if packed {
+ return sizeZigzag32PackedSlice, appendZigzag32PackedSlice
+ }
+ return sizeZigzag32Slice, appendZigzag32Slice
+ }
+ if nozero {
+ return sizeZigzag32ValueNoZero, appendZigzag32ValueNoZero
+ }
+ return sizeZigzag32Value, appendZigzag32Value
+ }
+ case reflect.Uint64:
+ switch encoding {
+ case "fixed64":
+ if pointer {
+ return sizeFixed64Ptr, appendFixed64Ptr
+ }
+ if slice {
+ if packed {
+ return sizeFixed64PackedSlice, appendFixed64PackedSlice
+ }
+ return sizeFixed64Slice, appendFixed64Slice
+ }
+ if nozero {
+ return sizeFixed64ValueNoZero, appendFixed64ValueNoZero
+ }
+ return sizeFixed64Value, appendFixed64Value
+ case "varint":
+ if pointer {
+ return sizeVarint64Ptr, appendVarint64Ptr
+ }
+ if slice {
+ if packed {
+ return sizeVarint64PackedSlice, appendVarint64PackedSlice
+ }
+ return sizeVarint64Slice, appendVarint64Slice
+ }
+ if nozero {
+ return sizeVarint64ValueNoZero, appendVarint64ValueNoZero
+ }
+ return sizeVarint64Value, appendVarint64Value
+ }
+ case reflect.Int64:
+ switch encoding {
+ case "fixed64":
+ if pointer {
+ return sizeFixedS64Ptr, appendFixedS64Ptr
+ }
+ if slice {
+ if packed {
+ return sizeFixedS64PackedSlice, appendFixedS64PackedSlice
+ }
+ return sizeFixedS64Slice, appendFixedS64Slice
+ }
+ if nozero {
+ return sizeFixedS64ValueNoZero, appendFixedS64ValueNoZero
+ }
+ return sizeFixedS64Value, appendFixedS64Value
+ case "varint":
+ if pointer {
+ return sizeVarintS64Ptr, appendVarintS64Ptr
+ }
+ if slice {
+ if packed {
+ return sizeVarintS64PackedSlice, appendVarintS64PackedSlice
+ }
+ return sizeVarintS64Slice, appendVarintS64Slice
+ }
+ if nozero {
+ return sizeVarintS64ValueNoZero, appendVarintS64ValueNoZero
+ }
+ return sizeVarintS64Value, appendVarintS64Value
+ case "zigzag64":
+ if pointer {
+ return sizeZigzag64Ptr, appendZigzag64Ptr
+ }
+ if slice {
+ if packed {
+ return sizeZigzag64PackedSlice, appendZigzag64PackedSlice
+ }
+ return sizeZigzag64Slice, appendZigzag64Slice
+ }
+ if nozero {
+ return sizeZigzag64ValueNoZero, appendZigzag64ValueNoZero
+ }
+ return sizeZigzag64Value, appendZigzag64Value
+ }
+ case reflect.Float32:
+ if pointer {
+ return sizeFloat32Ptr, appendFloat32Ptr
+ }
+ if slice {
+ if packed {
+ return sizeFloat32PackedSlice, appendFloat32PackedSlice
+ }
+ return sizeFloat32Slice, appendFloat32Slice
+ }
+ if nozero {
+ return sizeFloat32ValueNoZero, appendFloat32ValueNoZero
+ }
+ return sizeFloat32Value, appendFloat32Value
+ case reflect.Float64:
+ if pointer {
+ return sizeFloat64Ptr, appendFloat64Ptr
+ }
+ if slice {
+ if packed {
+ return sizeFloat64PackedSlice, appendFloat64PackedSlice
+ }
+ return sizeFloat64Slice, appendFloat64Slice
+ }
+ if nozero {
+ return sizeFloat64ValueNoZero, appendFloat64ValueNoZero
+ }
+ return sizeFloat64Value, appendFloat64Value
+ case reflect.String:
+ if validateUTF8 {
+ if pointer {
+ return sizeStringPtr, appendUTF8StringPtr
+ }
+ if slice {
+ return sizeStringSlice, appendUTF8StringSlice
+ }
+ if nozero {
+ return sizeStringValueNoZero, appendUTF8StringValueNoZero
+ }
+ return sizeStringValue, appendUTF8StringValue
+ }
+ if pointer {
+ return sizeStringPtr, appendStringPtr
+ }
+ if slice {
+ return sizeStringSlice, appendStringSlice
+ }
+ if nozero {
+ return sizeStringValueNoZero, appendStringValueNoZero
+ }
+ return sizeStringValue, appendStringValue
+ case reflect.Slice:
+ if slice {
+ return sizeBytesSlice, appendBytesSlice
+ }
+ if oneof {
+ // Oneof bytes field may also have "proto3" tag.
+ // We want to marshal it as a oneof field. Do this
+ // check before the proto3 check.
+ return sizeBytesOneof, appendBytesOneof
+ }
+ if proto3 {
+ return sizeBytes3, appendBytes3
+ }
+ return sizeBytes, appendBytes
+ case reflect.Struct:
+ switch encoding {
+ case "group":
+ if slice {
+ return makeGroupSliceMarshaler(getMarshalInfo(t))
+ }
+ return makeGroupMarshaler(getMarshalInfo(t))
+ case "bytes":
+ if slice {
+ return makeMessageSliceMarshaler(getMarshalInfo(t))
+ }
+ return makeMessageMarshaler(getMarshalInfo(t))
+ }
+ }
+ panic(fmt.Sprintf("unknown or mismatched type: type: %v, wire type: %v", t, encoding))
+}
+
+// Below are functions to size/marshal a specific type of a field.
+// They are stored in the field's info, and called by function pointers.
+// They have type sizer or marshaler.
+
+func sizeFixed32Value(_ pointer, tagsize int) int {
+ return 4 + tagsize
+}
+func sizeFixed32ValueNoZero(ptr pointer, tagsize int) int {
+ v := *ptr.toUint32()
+ if v == 0 {
+ return 0
+ }
+ return 4 + tagsize
+}
+func sizeFixed32Ptr(ptr pointer, tagsize int) int {
+ p := *ptr.toUint32Ptr()
+ if p == nil {
+ return 0
+ }
+ return 4 + tagsize
+}
+func sizeFixed32Slice(ptr pointer, tagsize int) int {
+ s := *ptr.toUint32Slice()
+ return (4 + tagsize) * len(s)
+}
+func sizeFixed32PackedSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toUint32Slice()
+ if len(s) == 0 {
+ return 0
+ }
+ return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize
+}
+func sizeFixedS32Value(_ pointer, tagsize int) int {
+ return 4 + tagsize
+}
+func sizeFixedS32ValueNoZero(ptr pointer, tagsize int) int {
+ v := *ptr.toInt32()
+ if v == 0 {
+ return 0
+ }
+ return 4 + tagsize
+}
+func sizeFixedS32Ptr(ptr pointer, tagsize int) int {
+ p := ptr.getInt32Ptr()
+ if p == nil {
+ return 0
+ }
+ return 4 + tagsize
+}
+func sizeFixedS32Slice(ptr pointer, tagsize int) int {
+ s := ptr.getInt32Slice()
+ return (4 + tagsize) * len(s)
+}
+func sizeFixedS32PackedSlice(ptr pointer, tagsize int) int {
+ s := ptr.getInt32Slice()
+ if len(s) == 0 {
+ return 0
+ }
+ return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize
+}
+func sizeFloat32Value(_ pointer, tagsize int) int {
+ return 4 + tagsize
+}
+func sizeFloat32ValueNoZero(ptr pointer, tagsize int) int {
+ v := math.Float32bits(*ptr.toFloat32())
+ if v == 0 {
+ return 0
+ }
+ return 4 + tagsize
+}
+func sizeFloat32Ptr(ptr pointer, tagsize int) int {
+ p := *ptr.toFloat32Ptr()
+ if p == nil {
+ return 0
+ }
+ return 4 + tagsize
+}
+func sizeFloat32Slice(ptr pointer, tagsize int) int {
+ s := *ptr.toFloat32Slice()
+ return (4 + tagsize) * len(s)
+}
+func sizeFloat32PackedSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toFloat32Slice()
+ if len(s) == 0 {
+ return 0
+ }
+ return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize
+}
+func sizeFixed64Value(_ pointer, tagsize int) int {
+ return 8 + tagsize
+}
+func sizeFixed64ValueNoZero(ptr pointer, tagsize int) int {
+ v := *ptr.toUint64()
+ if v == 0 {
+ return 0
+ }
+ return 8 + tagsize
+}
+func sizeFixed64Ptr(ptr pointer, tagsize int) int {
+ p := *ptr.toUint64Ptr()
+ if p == nil {
+ return 0
+ }
+ return 8 + tagsize
+}
+func sizeFixed64Slice(ptr pointer, tagsize int) int {
+ s := *ptr.toUint64Slice()
+ return (8 + tagsize) * len(s)
+}
+func sizeFixed64PackedSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toUint64Slice()
+ if len(s) == 0 {
+ return 0
+ }
+ return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize
+}
+func sizeFixedS64Value(_ pointer, tagsize int) int {
+ return 8 + tagsize
+}
+func sizeFixedS64ValueNoZero(ptr pointer, tagsize int) int {
+ v := *ptr.toInt64()
+ if v == 0 {
+ return 0
+ }
+ return 8 + tagsize
+}
+func sizeFixedS64Ptr(ptr pointer, tagsize int) int {
+ p := *ptr.toInt64Ptr()
+ if p == nil {
+ return 0
+ }
+ return 8 + tagsize
+}
+func sizeFixedS64Slice(ptr pointer, tagsize int) int {
+ s := *ptr.toInt64Slice()
+ return (8 + tagsize) * len(s)
+}
+func sizeFixedS64PackedSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toInt64Slice()
+ if len(s) == 0 {
+ return 0
+ }
+ return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize
+}
+func sizeFloat64Value(_ pointer, tagsize int) int {
+ return 8 + tagsize
+}
+func sizeFloat64ValueNoZero(ptr pointer, tagsize int) int {
+ v := math.Float64bits(*ptr.toFloat64())
+ if v == 0 {
+ return 0
+ }
+ return 8 + tagsize
+}
+func sizeFloat64Ptr(ptr pointer, tagsize int) int {
+ p := *ptr.toFloat64Ptr()
+ if p == nil {
+ return 0
+ }
+ return 8 + tagsize
+}
+func sizeFloat64Slice(ptr pointer, tagsize int) int {
+ s := *ptr.toFloat64Slice()
+ return (8 + tagsize) * len(s)
+}
+func sizeFloat64PackedSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toFloat64Slice()
+ if len(s) == 0 {
+ return 0
+ }
+ return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize
+}
+func sizeVarint32Value(ptr pointer, tagsize int) int {
+ v := *ptr.toUint32()
+ return SizeVarint(uint64(v)) + tagsize
+}
+func sizeVarint32ValueNoZero(ptr pointer, tagsize int) int {
+ v := *ptr.toUint32()
+ if v == 0 {
+ return 0
+ }
+ return SizeVarint(uint64(v)) + tagsize
+}
+func sizeVarint32Ptr(ptr pointer, tagsize int) int {
+ p := *ptr.toUint32Ptr()
+ if p == nil {
+ return 0
+ }
+ return SizeVarint(uint64(*p)) + tagsize
+}
+func sizeVarint32Slice(ptr pointer, tagsize int) int {
+ s := *ptr.toUint32Slice()
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64(v)) + tagsize
+ }
+ return n
+}
+func sizeVarint32PackedSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toUint32Slice()
+ if len(s) == 0 {
+ return 0
+ }
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64(v))
+ }
+ return n + SizeVarint(uint64(n)) + tagsize
+}
+func sizeVarintS32Value(ptr pointer, tagsize int) int {
+ v := *ptr.toInt32()
+ return SizeVarint(uint64(v)) + tagsize
+}
+func sizeVarintS32ValueNoZero(ptr pointer, tagsize int) int {
+ v := *ptr.toInt32()
+ if v == 0 {
+ return 0
+ }
+ return SizeVarint(uint64(v)) + tagsize
+}
+func sizeVarintS32Ptr(ptr pointer, tagsize int) int {
+ p := ptr.getInt32Ptr()
+ if p == nil {
+ return 0
+ }
+ return SizeVarint(uint64(*p)) + tagsize
+}
+func sizeVarintS32Slice(ptr pointer, tagsize int) int {
+ s := ptr.getInt32Slice()
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64(v)) + tagsize
+ }
+ return n
+}
+func sizeVarintS32PackedSlice(ptr pointer, tagsize int) int {
+ s := ptr.getInt32Slice()
+ if len(s) == 0 {
+ return 0
+ }
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64(v))
+ }
+ return n + SizeVarint(uint64(n)) + tagsize
+}
+func sizeVarint64Value(ptr pointer, tagsize int) int {
+ v := *ptr.toUint64()
+ return SizeVarint(v) + tagsize
+}
+func sizeVarint64ValueNoZero(ptr pointer, tagsize int) int {
+ v := *ptr.toUint64()
+ if v == 0 {
+ return 0
+ }
+ return SizeVarint(v) + tagsize
+}
+func sizeVarint64Ptr(ptr pointer, tagsize int) int {
+ p := *ptr.toUint64Ptr()
+ if p == nil {
+ return 0
+ }
+ return SizeVarint(*p) + tagsize
+}
+func sizeVarint64Slice(ptr pointer, tagsize int) int {
+ s := *ptr.toUint64Slice()
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(v) + tagsize
+ }
+ return n
+}
+func sizeVarint64PackedSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toUint64Slice()
+ if len(s) == 0 {
+ return 0
+ }
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(v)
+ }
+ return n + SizeVarint(uint64(n)) + tagsize
+}
+func sizeVarintS64Value(ptr pointer, tagsize int) int {
+ v := *ptr.toInt64()
+ return SizeVarint(uint64(v)) + tagsize
+}
+func sizeVarintS64ValueNoZero(ptr pointer, tagsize int) int {
+ v := *ptr.toInt64()
+ if v == 0 {
+ return 0
+ }
+ return SizeVarint(uint64(v)) + tagsize
+}
+func sizeVarintS64Ptr(ptr pointer, tagsize int) int {
+ p := *ptr.toInt64Ptr()
+ if p == nil {
+ return 0
+ }
+ return SizeVarint(uint64(*p)) + tagsize
+}
+func sizeVarintS64Slice(ptr pointer, tagsize int) int {
+ s := *ptr.toInt64Slice()
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64(v)) + tagsize
+ }
+ return n
+}
+func sizeVarintS64PackedSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toInt64Slice()
+ if len(s) == 0 {
+ return 0
+ }
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64(v))
+ }
+ return n + SizeVarint(uint64(n)) + tagsize
+}
+func sizeZigzag32Value(ptr pointer, tagsize int) int {
+ v := *ptr.toInt32()
+ return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize
+}
+func sizeZigzag32ValueNoZero(ptr pointer, tagsize int) int {
+ v := *ptr.toInt32()
+ if v == 0 {
+ return 0
+ }
+ return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize
+}
+func sizeZigzag32Ptr(ptr pointer, tagsize int) int {
+ p := ptr.getInt32Ptr()
+ if p == nil {
+ return 0
+ }
+ v := *p
+ return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize
+}
+func sizeZigzag32Slice(ptr pointer, tagsize int) int {
+ s := ptr.getInt32Slice()
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize
+ }
+ return n
+}
+func sizeZigzag32PackedSlice(ptr pointer, tagsize int) int {
+ s := ptr.getInt32Slice()
+ if len(s) == 0 {
+ return 0
+ }
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31))))
+ }
+ return n + SizeVarint(uint64(n)) + tagsize
+}
+func sizeZigzag64Value(ptr pointer, tagsize int) int {
+ v := *ptr.toInt64()
+ return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize
+}
+func sizeZigzag64ValueNoZero(ptr pointer, tagsize int) int {
+ v := *ptr.toInt64()
+ if v == 0 {
+ return 0
+ }
+ return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize
+}
+func sizeZigzag64Ptr(ptr pointer, tagsize int) int {
+ p := *ptr.toInt64Ptr()
+ if p == nil {
+ return 0
+ }
+ v := *p
+ return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize
+}
+func sizeZigzag64Slice(ptr pointer, tagsize int) int {
+ s := *ptr.toInt64Slice()
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize
+ }
+ return n
+}
+func sizeZigzag64PackedSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toInt64Slice()
+ if len(s) == 0 {
+ return 0
+ }
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63)))
+ }
+ return n + SizeVarint(uint64(n)) + tagsize
+}
+func sizeBoolValue(_ pointer, tagsize int) int {
+ return 1 + tagsize
+}
+func sizeBoolValueNoZero(ptr pointer, tagsize int) int {
+ v := *ptr.toBool()
+ if !v {
+ return 0
+ }
+ return 1 + tagsize
+}
+func sizeBoolPtr(ptr pointer, tagsize int) int {
+ p := *ptr.toBoolPtr()
+ if p == nil {
+ return 0
+ }
+ return 1 + tagsize
+}
+func sizeBoolSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toBoolSlice()
+ return (1 + tagsize) * len(s)
+}
+func sizeBoolPackedSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toBoolSlice()
+ if len(s) == 0 {
+ return 0
+ }
+ return len(s) + SizeVarint(uint64(len(s))) + tagsize
+}
+func sizeStringValue(ptr pointer, tagsize int) int {
+ v := *ptr.toString()
+ return len(v) + SizeVarint(uint64(len(v))) + tagsize
+}
+func sizeStringValueNoZero(ptr pointer, tagsize int) int {
+ v := *ptr.toString()
+ if v == "" {
+ return 0
+ }
+ return len(v) + SizeVarint(uint64(len(v))) + tagsize
+}
+func sizeStringPtr(ptr pointer, tagsize int) int {
+ p := *ptr.toStringPtr()
+ if p == nil {
+ return 0
+ }
+ v := *p
+ return len(v) + SizeVarint(uint64(len(v))) + tagsize
+}
+func sizeStringSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toStringSlice()
+ n := 0
+ for _, v := range s {
+ n += len(v) + SizeVarint(uint64(len(v))) + tagsize
+ }
+ return n
+}
+func sizeBytes(ptr pointer, tagsize int) int {
+ v := *ptr.toBytes()
+ if v == nil {
+ return 0
+ }
+ return len(v) + SizeVarint(uint64(len(v))) + tagsize
+}
+func sizeBytes3(ptr pointer, tagsize int) int {
+ v := *ptr.toBytes()
+ if len(v) == 0 {
+ return 0
+ }
+ return len(v) + SizeVarint(uint64(len(v))) + tagsize
+}
+func sizeBytesOneof(ptr pointer, tagsize int) int {
+ v := *ptr.toBytes()
+ return len(v) + SizeVarint(uint64(len(v))) + tagsize
+}
+func sizeBytesSlice(ptr pointer, tagsize int) int {
+ s := *ptr.toBytesSlice()
+ n := 0
+ for _, v := range s {
+ n += len(v) + SizeVarint(uint64(len(v))) + tagsize
+ }
+ return n
+}
+
+// appendFixed32 appends an encoded fixed32 to b.
+func appendFixed32(b []byte, v uint32) []byte {
+ b = append(b,
+ byte(v),
+ byte(v>>8),
+ byte(v>>16),
+ byte(v>>24))
+ return b
+}
+
+// appendFixed64 appends an encoded fixed64 to b.
+func appendFixed64(b []byte, v uint64) []byte {
+ b = append(b,
+ byte(v),
+ byte(v>>8),
+ byte(v>>16),
+ byte(v>>24),
+ byte(v>>32),
+ byte(v>>40),
+ byte(v>>48),
+ byte(v>>56))
+ return b
+}
+
+// appendVarint appends an encoded varint to b.
+func appendVarint(b []byte, v uint64) []byte {
+ // TODO: make 1-byte (maybe 2-byte) case inline-able, once we
+ // have non-leaf inliner.
+ switch {
+ case v < 1<<7:
+ b = append(b, byte(v))
+ case v < 1<<14:
+ b = append(b,
+ byte(v&0x7f|0x80),
+ byte(v>>7))
+ case v < 1<<21:
+ b = append(b,
+ byte(v&0x7f|0x80),
+ byte((v>>7)&0x7f|0x80),
+ byte(v>>14))
+ case v < 1<<28:
+ b = append(b,
+ byte(v&0x7f|0x80),
+ byte((v>>7)&0x7f|0x80),
+ byte((v>>14)&0x7f|0x80),
+ byte(v>>21))
+ case v < 1<<35:
+ b = append(b,
+ byte(v&0x7f|0x80),
+ byte((v>>7)&0x7f|0x80),
+ byte((v>>14)&0x7f|0x80),
+ byte((v>>21)&0x7f|0x80),
+ byte(v>>28))
+ case v < 1<<42:
+ b = append(b,
+ byte(v&0x7f|0x80),
+ byte((v>>7)&0x7f|0x80),
+ byte((v>>14)&0x7f|0x80),
+ byte((v>>21)&0x7f|0x80),
+ byte((v>>28)&0x7f|0x80),
+ byte(v>>35))
+ case v < 1<<49:
+ b = append(b,
+ byte(v&0x7f|0x80),
+ byte((v>>7)&0x7f|0x80),
+ byte((v>>14)&0x7f|0x80),
+ byte((v>>21)&0x7f|0x80),
+ byte((v>>28)&0x7f|0x80),
+ byte((v>>35)&0x7f|0x80),
+ byte(v>>42))
+ case v < 1<<56:
+ b = append(b,
+ byte(v&0x7f|0x80),
+ byte((v>>7)&0x7f|0x80),
+ byte((v>>14)&0x7f|0x80),
+ byte((v>>21)&0x7f|0x80),
+ byte((v>>28)&0x7f|0x80),
+ byte((v>>35)&0x7f|0x80),
+ byte((v>>42)&0x7f|0x80),
+ byte(v>>49))
+ case v < 1<<63:
+ b = append(b,
+ byte(v&0x7f|0x80),
+ byte((v>>7)&0x7f|0x80),
+ byte((v>>14)&0x7f|0x80),
+ byte((v>>21)&0x7f|0x80),
+ byte((v>>28)&0x7f|0x80),
+ byte((v>>35)&0x7f|0x80),
+ byte((v>>42)&0x7f|0x80),
+ byte((v>>49)&0x7f|0x80),
+ byte(v>>56))
+ default:
+ b = append(b,
+ byte(v&0x7f|0x80),
+ byte((v>>7)&0x7f|0x80),
+ byte((v>>14)&0x7f|0x80),
+ byte((v>>21)&0x7f|0x80),
+ byte((v>>28)&0x7f|0x80),
+ byte((v>>35)&0x7f|0x80),
+ byte((v>>42)&0x7f|0x80),
+ byte((v>>49)&0x7f|0x80),
+ byte((v>>56)&0x7f|0x80),
+ 1)
+ }
+ return b
+}
+
+func appendFixed32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toUint32()
+ b = appendVarint(b, wiretag)
+ b = appendFixed32(b, v)
+ return b, nil
+}
+func appendFixed32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toUint32()
+ if v == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendFixed32(b, v)
+ return b, nil
+}
+func appendFixed32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := *ptr.toUint32Ptr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendFixed32(b, *p)
+ return b, nil
+}
+func appendFixed32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toUint32Slice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendFixed32(b, v)
+ }
+ return b, nil
+}
+func appendFixed32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toUint32Slice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ b = appendVarint(b, uint64(4*len(s)))
+ for _, v := range s {
+ b = appendFixed32(b, v)
+ }
+ return b, nil
+}
+func appendFixedS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toInt32()
+ b = appendVarint(b, wiretag)
+ b = appendFixed32(b, uint32(v))
+ return b, nil
+}
+func appendFixedS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toInt32()
+ if v == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendFixed32(b, uint32(v))
+ return b, nil
+}
+func appendFixedS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := ptr.getInt32Ptr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendFixed32(b, uint32(*p))
+ return b, nil
+}
+func appendFixedS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := ptr.getInt32Slice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendFixed32(b, uint32(v))
+ }
+ return b, nil
+}
+func appendFixedS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := ptr.getInt32Slice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ b = appendVarint(b, uint64(4*len(s)))
+ for _, v := range s {
+ b = appendFixed32(b, uint32(v))
+ }
+ return b, nil
+}
+func appendFloat32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := math.Float32bits(*ptr.toFloat32())
+ b = appendVarint(b, wiretag)
+ b = appendFixed32(b, v)
+ return b, nil
+}
+func appendFloat32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := math.Float32bits(*ptr.toFloat32())
+ if v == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendFixed32(b, v)
+ return b, nil
+}
+func appendFloat32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := *ptr.toFloat32Ptr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendFixed32(b, math.Float32bits(*p))
+ return b, nil
+}
+func appendFloat32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toFloat32Slice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendFixed32(b, math.Float32bits(v))
+ }
+ return b, nil
+}
+func appendFloat32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toFloat32Slice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ b = appendVarint(b, uint64(4*len(s)))
+ for _, v := range s {
+ b = appendFixed32(b, math.Float32bits(v))
+ }
+ return b, nil
+}
+func appendFixed64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toUint64()
+ b = appendVarint(b, wiretag)
+ b = appendFixed64(b, v)
+ return b, nil
+}
+func appendFixed64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toUint64()
+ if v == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendFixed64(b, v)
+ return b, nil
+}
+func appendFixed64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := *ptr.toUint64Ptr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendFixed64(b, *p)
+ return b, nil
+}
+func appendFixed64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toUint64Slice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendFixed64(b, v)
+ }
+ return b, nil
+}
+func appendFixed64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toUint64Slice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ b = appendVarint(b, uint64(8*len(s)))
+ for _, v := range s {
+ b = appendFixed64(b, v)
+ }
+ return b, nil
+}
+func appendFixedS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toInt64()
+ b = appendVarint(b, wiretag)
+ b = appendFixed64(b, uint64(v))
+ return b, nil
+}
+func appendFixedS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toInt64()
+ if v == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendFixed64(b, uint64(v))
+ return b, nil
+}
+func appendFixedS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := *ptr.toInt64Ptr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendFixed64(b, uint64(*p))
+ return b, nil
+}
+func appendFixedS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toInt64Slice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendFixed64(b, uint64(v))
+ }
+ return b, nil
+}
+func appendFixedS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toInt64Slice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ b = appendVarint(b, uint64(8*len(s)))
+ for _, v := range s {
+ b = appendFixed64(b, uint64(v))
+ }
+ return b, nil
+}
+func appendFloat64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := math.Float64bits(*ptr.toFloat64())
+ b = appendVarint(b, wiretag)
+ b = appendFixed64(b, v)
+ return b, nil
+}
+func appendFloat64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := math.Float64bits(*ptr.toFloat64())
+ if v == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendFixed64(b, v)
+ return b, nil
+}
+func appendFloat64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := *ptr.toFloat64Ptr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendFixed64(b, math.Float64bits(*p))
+ return b, nil
+}
+func appendFloat64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toFloat64Slice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendFixed64(b, math.Float64bits(v))
+ }
+ return b, nil
+}
+func appendFloat64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toFloat64Slice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ b = appendVarint(b, uint64(8*len(s)))
+ for _, v := range s {
+ b = appendFixed64(b, math.Float64bits(v))
+ }
+ return b, nil
+}
+func appendVarint32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toUint32()
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(v))
+ return b, nil
+}
+func appendVarint32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toUint32()
+ if v == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(v))
+ return b, nil
+}
+func appendVarint32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := *ptr.toUint32Ptr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(*p))
+ return b, nil
+}
+func appendVarint32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toUint32Slice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(v))
+ }
+ return b, nil
+}
+func appendVarint32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toUint32Slice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ // compute size
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64(v))
+ }
+ b = appendVarint(b, uint64(n))
+ for _, v := range s {
+ b = appendVarint(b, uint64(v))
+ }
+ return b, nil
+}
+func appendVarintS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toInt32()
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(v))
+ return b, nil
+}
+func appendVarintS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toInt32()
+ if v == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(v))
+ return b, nil
+}
+func appendVarintS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := ptr.getInt32Ptr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(*p))
+ return b, nil
+}
+func appendVarintS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := ptr.getInt32Slice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(v))
+ }
+ return b, nil
+}
+func appendVarintS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := ptr.getInt32Slice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ // compute size
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64(v))
+ }
+ b = appendVarint(b, uint64(n))
+ for _, v := range s {
+ b = appendVarint(b, uint64(v))
+ }
+ return b, nil
+}
+func appendVarint64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toUint64()
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, v)
+ return b, nil
+}
+func appendVarint64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toUint64()
+ if v == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, v)
+ return b, nil
+}
+func appendVarint64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := *ptr.toUint64Ptr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, *p)
+ return b, nil
+}
+func appendVarint64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toUint64Slice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, v)
+ }
+ return b, nil
+}
+func appendVarint64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toUint64Slice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ // compute size
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(v)
+ }
+ b = appendVarint(b, uint64(n))
+ for _, v := range s {
+ b = appendVarint(b, v)
+ }
+ return b, nil
+}
+func appendVarintS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toInt64()
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(v))
+ return b, nil
+}
+func appendVarintS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toInt64()
+ if v == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(v))
+ return b, nil
+}
+func appendVarintS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := *ptr.toInt64Ptr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(*p))
+ return b, nil
+}
+func appendVarintS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toInt64Slice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(v))
+ }
+ return b, nil
+}
+func appendVarintS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toInt64Slice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ // compute size
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64(v))
+ }
+ b = appendVarint(b, uint64(n))
+ for _, v := range s {
+ b = appendVarint(b, uint64(v))
+ }
+ return b, nil
+}
+func appendZigzag32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toInt32()
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31))))
+ return b, nil
+}
+func appendZigzag32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toInt32()
+ if v == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31))))
+ return b, nil
+}
+func appendZigzag32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := ptr.getInt32Ptr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ v := *p
+ b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31))))
+ return b, nil
+}
+func appendZigzag32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := ptr.getInt32Slice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31))))
+ }
+ return b, nil
+}
+func appendZigzag32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := ptr.getInt32Slice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ // compute size
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31))))
+ }
+ b = appendVarint(b, uint64(n))
+ for _, v := range s {
+ b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31))))
+ }
+ return b, nil
+}
+func appendZigzag64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toInt64()
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63)))
+ return b, nil
+}
+func appendZigzag64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toInt64()
+ if v == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63)))
+ return b, nil
+}
+func appendZigzag64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := *ptr.toInt64Ptr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ v := *p
+ b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63)))
+ return b, nil
+}
+func appendZigzag64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toInt64Slice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63)))
+ }
+ return b, nil
+}
+func appendZigzag64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toInt64Slice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ // compute size
+ n := 0
+ for _, v := range s {
+ n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63)))
+ }
+ b = appendVarint(b, uint64(n))
+ for _, v := range s {
+ b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63)))
+ }
+ return b, nil
+}
+func appendBoolValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toBool()
+ b = appendVarint(b, wiretag)
+ if v {
+ b = append(b, 1)
+ } else {
+ b = append(b, 0)
+ }
+ return b, nil
+}
+func appendBoolValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toBool()
+ if !v {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = append(b, 1)
+ return b, nil
+}
+
+func appendBoolPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := *ptr.toBoolPtr()
+ if p == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ if *p {
+ b = append(b, 1)
+ } else {
+ b = append(b, 0)
+ }
+ return b, nil
+}
+func appendBoolSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toBoolSlice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ if v {
+ b = append(b, 1)
+ } else {
+ b = append(b, 0)
+ }
+ }
+ return b, nil
+}
+func appendBoolPackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toBoolSlice()
+ if len(s) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag&^7|WireBytes)
+ b = appendVarint(b, uint64(len(s)))
+ for _, v := range s {
+ if v {
+ b = append(b, 1)
+ } else {
+ b = append(b, 0)
+ }
+ }
+ return b, nil
+}
+func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toString()
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(len(v)))
+ b = append(b, v...)
+ return b, nil
+}
+func appendStringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toString()
+ if v == "" {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(len(v)))
+ b = append(b, v...)
+ return b, nil
+}
+func appendStringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ p := *ptr.toStringPtr()
+ if p == nil {
+ return b, nil
+ }
+ v := *p
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(len(v)))
+ b = append(b, v...)
+ return b, nil
+}
+func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toStringSlice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(len(v)))
+ b = append(b, v...)
+ }
+ return b, nil
+}
+func appendUTF8StringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ var invalidUTF8 bool
+ v := *ptr.toString()
+ if !utf8.ValidString(v) {
+ invalidUTF8 = true
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(len(v)))
+ b = append(b, v...)
+ if invalidUTF8 {
+ return b, errInvalidUTF8
+ }
+ return b, nil
+}
+func appendUTF8StringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ var invalidUTF8 bool
+ v := *ptr.toString()
+ if v == "" {
+ return b, nil
+ }
+ if !utf8.ValidString(v) {
+ invalidUTF8 = true
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(len(v)))
+ b = append(b, v...)
+ if invalidUTF8 {
+ return b, errInvalidUTF8
+ }
+ return b, nil
+}
+func appendUTF8StringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ var invalidUTF8 bool
+ p := *ptr.toStringPtr()
+ if p == nil {
+ return b, nil
+ }
+ v := *p
+ if !utf8.ValidString(v) {
+ invalidUTF8 = true
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(len(v)))
+ b = append(b, v...)
+ if invalidUTF8 {
+ return b, errInvalidUTF8
+ }
+ return b, nil
+}
+func appendUTF8StringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ var invalidUTF8 bool
+ s := *ptr.toStringSlice()
+ for _, v := range s {
+ if !utf8.ValidString(v) {
+ invalidUTF8 = true
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(len(v)))
+ b = append(b, v...)
+ }
+ if invalidUTF8 {
+ return b, errInvalidUTF8
+ }
+ return b, nil
+}
+func appendBytes(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toBytes()
+ if v == nil {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(len(v)))
+ b = append(b, v...)
+ return b, nil
+}
+func appendBytes3(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toBytes()
+ if len(v) == 0 {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(len(v)))
+ b = append(b, v...)
+ return b, nil
+}
+func appendBytesOneof(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ v := *ptr.toBytes()
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(len(v)))
+ b = append(b, v...)
+ return b, nil
+}
+func appendBytesSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
+ s := *ptr.toBytesSlice()
+ for _, v := range s {
+ b = appendVarint(b, wiretag)
+ b = appendVarint(b, uint64(len(v)))
+ b = append(b, v...)
+ }
+ return b, nil
+}
+
+// makeGroupMarshaler returns the sizer and marshaler for a group.
+// u is the marshal info of the underlying message.
+func makeGroupMarshaler(u *marshalInfo) (sizer, marshaler) {
+ return func(ptr pointer, tagsize int) int {
+ p := ptr.getPointer()
+ if p.isNil() {
+ return 0
+ }
+ return u.size(p) + 2*tagsize
+ },
+ func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
+ p := ptr.getPointer()
+ if p.isNil() {
+ return b, nil
+ }
+ var err error
+ b = appendVarint(b, wiretag) // start group
+ b, err = u.marshal(b, p, deterministic)
+ b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group
+ return b, err
+ }
+}
+
+// makeGroupSliceMarshaler returns the sizer and marshaler for a group slice.
+// u is the marshal info of the underlying message.
+func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
+ return func(ptr pointer, tagsize int) int {
+ s := ptr.getPointerSlice()
+ n := 0
+ for _, v := range s {
+ if v.isNil() {
+ continue
+ }
+ n += u.size(v) + 2*tagsize
+ }
+ return n
+ },
+ func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
+ s := ptr.getPointerSlice()
+ var err error
+ var nerr nonFatal
+ for _, v := range s {
+ if v.isNil() {
+ return b, errRepeatedHasNil
+ }
+ b = appendVarint(b, wiretag) // start group
+ b, err = u.marshal(b, v, deterministic)
+ b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group
+ if !nerr.Merge(err) {
+ if err == ErrNil {
+ err = errRepeatedHasNil
+ }
+ return b, err
+ }
+ }
+ return b, nerr.E
+ }
+}
+
+// makeMessageMarshaler returns the sizer and marshaler for a message field.
+// u is the marshal info of the message.
+func makeMessageMarshaler(u *marshalInfo) (sizer, marshaler) {
+ return func(ptr pointer, tagsize int) int {
+ p := ptr.getPointer()
+ if p.isNil() {
+ return 0
+ }
+ siz := u.size(p)
+ return siz + SizeVarint(uint64(siz)) + tagsize
+ },
+ func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
+ p := ptr.getPointer()
+ if p.isNil() {
+ return b, nil
+ }
+ b = appendVarint(b, wiretag)
+ siz := u.cachedsize(p)
+ b = appendVarint(b, uint64(siz))
+ return u.marshal(b, p, deterministic)
+ }
+}
+
+// makeMessageSliceMarshaler returns the sizer and marshaler for a message slice.
+// u is the marshal info of the message.
+func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
+ return func(ptr pointer, tagsize int) int {
+ s := ptr.getPointerSlice()
+ n := 0
+ for _, v := range s {
+ if v.isNil() {
+ continue
+ }
+ siz := u.size(v)
+ n += siz + SizeVarint(uint64(siz)) + tagsize
+ }
+ return n
+ },
+ func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
+ s := ptr.getPointerSlice()
+ var err error
+ var nerr nonFatal
+ for _, v := range s {
+ if v.isNil() {
+ return b, errRepeatedHasNil
+ }
+ b = appendVarint(b, wiretag)
+ siz := u.cachedsize(v)
+ b = appendVarint(b, uint64(siz))
+ b, err = u.marshal(b, v, deterministic)
+
+ if !nerr.Merge(err) {
+ if err == ErrNil {
+ err = errRepeatedHasNil
+ }
+ return b, err
+ }
+ }
+ return b, nerr.E
+ }
+}
+
+// makeMapMarshaler returns the sizer and marshaler for a map field.
+// f is the pointer to the reflect data structure of the field.
+func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
+ // figure out key and value type
+ t := f.Type
+ keyType := t.Key()
+ valType := t.Elem()
+ keyTags := strings.Split(f.Tag.Get("protobuf_key"), ",")
+ valTags := strings.Split(f.Tag.Get("protobuf_val"), ",")
+ keySizer, keyMarshaler := typeMarshaler(keyType, keyTags, false, false) // don't omit zero value in map
+ valSizer, valMarshaler := typeMarshaler(valType, valTags, false, false) // don't omit zero value in map
+ keyWireTag := 1<<3 | wiretype(keyTags[0])
+ valWireTag := 2<<3 | wiretype(valTags[0])
+
+ // We create an interface to get the addresses of the map key and value.
+ // If value is pointer-typed, the interface is a direct interface, the
+ // idata itself is the value. Otherwise, the idata is the pointer to the
+ // value.
+ // Key cannot be pointer-typed.
+ valIsPtr := valType.Kind() == reflect.Ptr
+
+ // If value is a message with nested maps, calling
+ // valSizer in marshal may be quadratic. We should use
+ // cached version in marshal (but not in size).
+ // If value is not message type, we don't have size cache,
+ // but it cannot be nested either. Just use valSizer.
+ valCachedSizer := valSizer
+ if valIsPtr && valType.Elem().Kind() == reflect.Struct {
+ u := getMarshalInfo(valType.Elem())
+ valCachedSizer = func(ptr pointer, tagsize int) int {
+ // Same as message sizer, but use cache.
+ p := ptr.getPointer()
+ if p.isNil() {
+ return 0
+ }
+ siz := u.cachedsize(p)
+ return siz + SizeVarint(uint64(siz)) + tagsize
+ }
+ }
+ return func(ptr pointer, tagsize int) int {
+ m := ptr.asPointerTo(t).Elem() // the map
+ n := 0
+ for _, k := range m.MapKeys() {
+ ki := k.Interface()
+ vi := m.MapIndex(k).Interface()
+ kaddr := toAddrPointer(&ki, false, false) // pointer to key
+ vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value
+ siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
+ n += siz + SizeVarint(uint64(siz)) + tagsize
+ }
+ return n
+ },
+ func(b []byte, ptr pointer, tag uint64, deterministic bool) ([]byte, error) {
+ m := ptr.asPointerTo(t).Elem() // the map
+ var err error
+ keys := m.MapKeys()
+ if len(keys) > 1 && deterministic {
+ sort.Sort(mapKeys(keys))
+ }
+
+ var nerr nonFatal
+ for _, k := range keys {
+ ki := k.Interface()
+ vi := m.MapIndex(k).Interface()
+ kaddr := toAddrPointer(&ki, false, false) // pointer to key
+ vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value
+ b = appendVarint(b, tag)
+ siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
+ b = appendVarint(b, uint64(siz))
+ b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic)
+ if !nerr.Merge(err) {
+ return b, err
+ }
+ b, err = valMarshaler(b, vaddr, valWireTag, deterministic)
+ if err != ErrNil && !nerr.Merge(err) { // allow nil value in map
+ return b, err
+ }
+ }
+ return b, nerr.E
+ }
+}
+
+// makeOneOfMarshaler returns the sizer and marshaler for a oneof field.
+// fi is the marshal info of the field.
+// f is the pointer to the reflect data structure of the field.
+func makeOneOfMarshaler(fi *marshalFieldInfo, f *reflect.StructField) (sizer, marshaler) {
+ // Oneof field is an interface. We need to get the actual data type on the fly.
+ t := f.Type
+ return func(ptr pointer, _ int) int {
+ p := ptr.getInterfacePointer()
+ if p.isNil() {
+ return 0
+ }
+ v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct
+ telem := v.Type()
+ e := fi.oneofElems[telem]
+ return e.sizer(p, e.tagsize)
+ },
+ func(b []byte, ptr pointer, _ uint64, deterministic bool) ([]byte, error) {
+ p := ptr.getInterfacePointer()
+ if p.isNil() {
+ return b, nil
+ }
+ v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct
+ telem := v.Type()
+ if telem.Field(0).Type.Kind() == reflect.Ptr && p.getPointer().isNil() {
+ return b, errOneofHasNil
+ }
+ e := fi.oneofElems[telem]
+ return e.marshaler(b, p, e.wiretag, deterministic)
+ }
+}
+
+// sizeExtensions computes the size of encoded data for a XXX_InternalExtensions field.
+func (u *marshalInfo) sizeExtensions(ext *XXX_InternalExtensions) int {
+ m, mu := ext.extensionsRead()
+ if m == nil {
+ return 0
+ }
+ mu.Lock()
+
+ n := 0
+ for _, e := range m {
+ if e.value == nil || e.desc == nil {
+ // Extension is only in its encoded form.
+ n += len(e.enc)
+ continue
+ }
+
+ // We don't skip extensions that have an encoded form set,
+ // because the extension value may have been mutated after
+ // the last time this function was called.
+ ei := u.getExtElemInfo(e.desc)
+ v := e.value
+ p := toAddrPointer(&v, ei.isptr, ei.deref)
+ n += ei.sizer(p, ei.tagsize)
+ }
+ mu.Unlock()
+ return n
+}
+
+// appendExtensions marshals a XXX_InternalExtensions field to the end of byte slice b.
+func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) {
+ m, mu := ext.extensionsRead()
+ if m == nil {
+ return b, nil
+ }
+ mu.Lock()
+ defer mu.Unlock()
+
+ var err error
+ var nerr nonFatal
+
+ // Fast-path for common cases: zero or one extensions.
+ // Don't bother sorting the keys.
+ if len(m) <= 1 {
+ for _, e := range m {
+ if e.value == nil || e.desc == nil {
+ // Extension is only in its encoded form.
+ b = append(b, e.enc...)
+ continue
+ }
+
+ // We don't skip extensions that have an encoded form set,
+ // because the extension value may have been mutated after
+ // the last time this function was called.
+
+ ei := u.getExtElemInfo(e.desc)
+ v := e.value
+ p := toAddrPointer(&v, ei.isptr, ei.deref)
+ b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
+ if !nerr.Merge(err) {
+ return b, err
+ }
+ }
+ return b, nerr.E
+ }
+
+ // Sort the keys to provide a deterministic encoding.
+ // Not sure this is required, but the old code does it.
+ keys := make([]int, 0, len(m))
+ for k := range m {
+ keys = append(keys, int(k))
+ }
+ sort.Ints(keys)
+
+ for _, k := range keys {
+ e := m[int32(k)]
+ if e.value == nil || e.desc == nil {
+ // Extension is only in its encoded form.
+ b = append(b, e.enc...)
+ continue
+ }
+
+ // We don't skip extensions that have an encoded form set,
+ // because the extension value may have been mutated after
+ // the last time this function was called.
+
+ ei := u.getExtElemInfo(e.desc)
+ v := e.value
+ p := toAddrPointer(&v, ei.isptr, ei.deref)
+ b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
+ if !nerr.Merge(err) {
+ return b, err
+ }
+ }
+ return b, nerr.E
+}
+
+// message set format is:
+// message MessageSet {
+// repeated group Item = 1 {
+// required int32 type_id = 2;
+// required string message = 3;
+// };
+// }
+
+// sizeMessageSet computes the size of encoded data for a XXX_InternalExtensions field
+// in message set format (above).
+func (u *marshalInfo) sizeMessageSet(ext *XXX_InternalExtensions) int {
+ m, mu := ext.extensionsRead()
+ if m == nil {
+ return 0
+ }
+ mu.Lock()
+
+ n := 0
+ for id, e := range m {
+ n += 2 // start group, end group. tag = 1 (size=1)
+ n += SizeVarint(uint64(id)) + 1 // type_id, tag = 2 (size=1)
+
+ if e.value == nil || e.desc == nil {
+ // Extension is only in its encoded form.
+ msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint
+ siz := len(msgWithLen)
+ n += siz + 1 // message, tag = 3 (size=1)
+ continue
+ }
+
+ // We don't skip extensions that have an encoded form set,
+ // because the extension value may have been mutated after
+ // the last time this function was called.
+
+ ei := u.getExtElemInfo(e.desc)
+ v := e.value
+ p := toAddrPointer(&v, ei.isptr, ei.deref)
+ n += ei.sizer(p, 1) // message, tag = 3 (size=1)
+ }
+ mu.Unlock()
+ return n
+}
+
+// appendMessageSet marshals a XXX_InternalExtensions field in message set format (above)
+// to the end of byte slice b.
+func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) {
+ m, mu := ext.extensionsRead()
+ if m == nil {
+ return b, nil
+ }
+ mu.Lock()
+ defer mu.Unlock()
+
+ var err error
+ var nerr nonFatal
+
+ // Fast-path for common cases: zero or one extensions.
+ // Don't bother sorting the keys.
+ if len(m) <= 1 {
+ for id, e := range m {
+ b = append(b, 1<<3|WireStartGroup)
+ b = append(b, 2<<3|WireVarint)
+ b = appendVarint(b, uint64(id))
+
+ if e.value == nil || e.desc == nil {
+ // Extension is only in its encoded form.
+ msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint
+ b = append(b, 3<<3|WireBytes)
+ b = append(b, msgWithLen...)
+ b = append(b, 1<<3|WireEndGroup)
+ continue
+ }
+
+ // We don't skip extensions that have an encoded form set,
+ // because the extension value may have been mutated after
+ // the last time this function was called.
+
+ ei := u.getExtElemInfo(e.desc)
+ v := e.value
+ p := toAddrPointer(&v, ei.isptr, ei.deref)
+ b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
+ if !nerr.Merge(err) {
+ return b, err
+ }
+ b = append(b, 1<<3|WireEndGroup)
+ }
+ return b, nerr.E
+ }
+
+ // Sort the keys to provide a deterministic encoding.
+ keys := make([]int, 0, len(m))
+ for k := range m {
+ keys = append(keys, int(k))
+ }
+ sort.Ints(keys)
+
+ for _, id := range keys {
+ e := m[int32(id)]
+ b = append(b, 1<<3|WireStartGroup)
+ b = append(b, 2<<3|WireVarint)
+ b = appendVarint(b, uint64(id))
+
+ if e.value == nil || e.desc == nil {
+ // Extension is only in its encoded form.
+ msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint
+ b = append(b, 3<<3|WireBytes)
+ b = append(b, msgWithLen...)
+ b = append(b, 1<<3|WireEndGroup)
+ continue
+ }
+
+ // We don't skip extensions that have an encoded form set,
+ // because the extension value may have been mutated after
+ // the last time this function was called.
+
+ ei := u.getExtElemInfo(e.desc)
+ v := e.value
+ p := toAddrPointer(&v, ei.isptr, ei.deref)
+ b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
+ b = append(b, 1<<3|WireEndGroup)
+ if !nerr.Merge(err) {
+ return b, err
+ }
+ }
+ return b, nerr.E
+}
+
+// sizeV1Extensions computes the size of encoded data for a V1-API extension field.
+func (u *marshalInfo) sizeV1Extensions(m map[int32]Extension) int {
+ if m == nil {
+ return 0
+ }
+
+ n := 0
+ for _, e := range m {
+ if e.value == nil || e.desc == nil {
+ // Extension is only in its encoded form.
+ n += len(e.enc)
+ continue
+ }
+
+ // We don't skip extensions that have an encoded form set,
+ // because the extension value may have been mutated after
+ // the last time this function was called.
+
+ ei := u.getExtElemInfo(e.desc)
+ v := e.value
+ p := toAddrPointer(&v, ei.isptr, ei.deref)
+ n += ei.sizer(p, ei.tagsize)
+ }
+ return n
+}
+
+// appendV1Extensions marshals a V1-API extension field to the end of byte slice b.
+func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, deterministic bool) ([]byte, error) {
+ if m == nil {
+ return b, nil
+ }
+
+ // Sort the keys to provide a deterministic encoding.
+ keys := make([]int, 0, len(m))
+ for k := range m {
+ keys = append(keys, int(k))
+ }
+ sort.Ints(keys)
+
+ var err error
+ var nerr nonFatal
+ for _, k := range keys {
+ e := m[int32(k)]
+ if e.value == nil || e.desc == nil {
+ // Extension is only in its encoded form.
+ b = append(b, e.enc...)
+ continue
+ }
+
+ // We don't skip extensions that have an encoded form set,
+ // because the extension value may have been mutated after
+ // the last time this function was called.
+
+ ei := u.getExtElemInfo(e.desc)
+ v := e.value
+ p := toAddrPointer(&v, ei.isptr, ei.deref)
+ b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
+ if !nerr.Merge(err) {
+ return b, err
+ }
+ }
+ return b, nerr.E
+}
+
+// newMarshaler is the interface representing objects that can marshal themselves.
+//
+// This exists to support protoc-gen-go generated messages.
+// The proto package will stop type-asserting to this interface in the future.
+//
+// DO NOT DEPEND ON THIS.
+type newMarshaler interface {
+ XXX_Size() int
+ XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
+}
+
+// Size returns the encoded size of a protocol buffer message.
+// This is the main entry point.
+func Size(pb Message) int {
+ if m, ok := pb.(newMarshaler); ok {
+ return m.XXX_Size()
+ }
+ if m, ok := pb.(Marshaler); ok {
+ // If the message can marshal itself, let it do it, for compatibility.
+ // NOTE: This is not efficient.
+ b, _ := m.Marshal()
+ return len(b)
+ }
+ // in case somehow we didn't generate the wrapper
+ if pb == nil {
+ return 0
+ }
+ var info InternalMessageInfo
+ return info.Size(pb)
+}
+
+// Marshal takes a protocol buffer message
+// and encodes it into the wire format, returning the data.
+// This is the main entry point.
+func Marshal(pb Message) ([]byte, error) {
+ if m, ok := pb.(newMarshaler); ok {
+ siz := m.XXX_Size()
+ b := make([]byte, 0, siz)
+ return m.XXX_Marshal(b, false)
+ }
+ if m, ok := pb.(Marshaler); ok {
+ // If the message can marshal itself, let it do it, for compatibility.
+ // NOTE: This is not efficient.
+ return m.Marshal()
+ }
+ // in case somehow we didn't generate the wrapper
+ if pb == nil {
+ return nil, ErrNil
+ }
+ var info InternalMessageInfo
+ siz := info.Size(pb)
+ b := make([]byte, 0, siz)
+ return info.Marshal(b, pb, false)
+}
+
+// Marshal takes a protocol buffer message
+// and encodes it into the wire format, writing the result to the
+// Buffer.
+// This is an alternative entry point. It is not necessary to use
+// a Buffer for most applications.
+func (p *Buffer) Marshal(pb Message) error {
+ var err error
+ if m, ok := pb.(newMarshaler); ok {
+ siz := m.XXX_Size()
+ p.grow(siz) // make sure buf has enough capacity
+ p.buf, err = m.XXX_Marshal(p.buf, p.deterministic)
+ return err
+ }
+ if m, ok := pb.(Marshaler); ok {
+ // If the message can marshal itself, let it do it, for compatibility.
+ // NOTE: This is not efficient.
+ b, err := m.Marshal()
+ p.buf = append(p.buf, b...)
+ return err
+ }
+ // in case somehow we didn't generate the wrapper
+ if pb == nil {
+ return ErrNil
+ }
+ var info InternalMessageInfo
+ siz := info.Size(pb)
+ p.grow(siz) // make sure buf has enough capacity
+ p.buf, err = info.Marshal(p.buf, pb, p.deterministic)
+ return err
+}
+
+// grow grows the buffer's capacity, if necessary, to guarantee space for
+// another n bytes. After grow(n), at least n bytes can be written to the
+// buffer without another allocation.
+func (p *Buffer) grow(n int) {
+ need := len(p.buf) + n
+ if need <= cap(p.buf) {
+ return
+ }
+ newCap := len(p.buf) * 2
+ if newCap < need {
+ newCap = need
+ }
+ p.buf = append(make([]byte, 0, newCap), p.buf...)
+}
diff --git a/vendor/github.com/golang/protobuf/proto/table_merge.go b/vendor/github.com/golang/protobuf/proto/table_merge.go
new file mode 100644
index 000000000..5525def6a
--- /dev/null
+++ b/vendor/github.com/golang/protobuf/proto/table_merge.go
@@ -0,0 +1,654 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2016 The Go Authors. All rights reserved.
+// https://github.com/golang/protobuf
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+ "sync"
+ "sync/atomic"
+)
+
+// Merge merges the src message into dst.
+// This assumes that dst and src of the same type and are non-nil.
+func (a *InternalMessageInfo) Merge(dst, src Message) {
+ mi := atomicLoadMergeInfo(&a.merge)
+ if mi == nil {
+ mi = getMergeInfo(reflect.TypeOf(dst).Elem())
+ atomicStoreMergeInfo(&a.merge, mi)
+ }
+ mi.merge(toPointer(&dst), toPointer(&src))
+}
+
+type mergeInfo struct {
+ typ reflect.Type
+
+ initialized int32 // 0: only typ is valid, 1: everything is valid
+ lock sync.Mutex
+
+ fields []mergeFieldInfo
+ unrecognized field // Offset of XXX_unrecognized
+}
+
+type mergeFieldInfo struct {
+ field field // Offset of field, guaranteed to be valid
+
+ // isPointer reports whether the value in the field is a pointer.
+ // This is true for the following situations:
+ // * Pointer to struct
+ // * Pointer to basic type (proto2 only)
+ // * Slice (first value in slice header is a pointer)
+ // * String (first value in string header is a pointer)
+ isPointer bool
+
+ // basicWidth reports the width of the field assuming that it is directly
+ // embedded in the struct (as is the case for basic types in proto3).
+ // The possible values are:
+ // 0: invalid
+ // 1: bool
+ // 4: int32, uint32, float32
+ // 8: int64, uint64, float64
+ basicWidth int
+
+ // Where dst and src are pointers to the types being merged.
+ merge func(dst, src pointer)
+}
+
+var (
+ mergeInfoMap = map[reflect.Type]*mergeInfo{}
+ mergeInfoLock sync.Mutex
+)
+
+func getMergeInfo(t reflect.Type) *mergeInfo {
+ mergeInfoLock.Lock()
+ defer mergeInfoLock.Unlock()
+ mi := mergeInfoMap[t]
+ if mi == nil {
+ mi = &mergeInfo{typ: t}
+ mergeInfoMap[t] = mi
+ }
+ return mi
+}
+
+// merge merges src into dst assuming they are both of type *mi.typ.
+func (mi *mergeInfo) merge(dst, src pointer) {
+ if dst.isNil() {
+ panic("proto: nil destination")
+ }
+ if src.isNil() {
+ return // Nothing to do.
+ }
+
+ if atomic.LoadInt32(&mi.initialized) == 0 {
+ mi.computeMergeInfo()
+ }
+
+ for _, fi := range mi.fields {
+ sfp := src.offset(fi.field)
+
+ // As an optimization, we can avoid the merge function call cost
+ // if we know for sure that the source will have no effect
+ // by checking if it is the zero value.
+ if unsafeAllowed {
+ if fi.isPointer && sfp.getPointer().isNil() { // Could be slice or string
+ continue
+ }
+ if fi.basicWidth > 0 {
+ switch {
+ case fi.basicWidth == 1 && !*sfp.toBool():
+ continue
+ case fi.basicWidth == 4 && *sfp.toUint32() == 0:
+ continue
+ case fi.basicWidth == 8 && *sfp.toUint64() == 0:
+ continue
+ }
+ }
+ }
+
+ dfp := dst.offset(fi.field)
+ fi.merge(dfp, sfp)
+ }
+
+ // TODO: Make this faster?
+ out := dst.asPointerTo(mi.typ).Elem()
+ in := src.asPointerTo(mi.typ).Elem()
+ if emIn, err := extendable(in.Addr().Interface()); err == nil {
+ emOut, _ := extendable(out.Addr().Interface())
+ mIn, muIn := emIn.extensionsRead()
+ if mIn != nil {
+ mOut := emOut.extensionsWrite()
+ muIn.Lock()
+ mergeExtension(mOut, mIn)
+ muIn.Unlock()
+ }
+ }
+
+ if mi.unrecognized.IsValid() {
+ if b := *src.offset(mi.unrecognized).toBytes(); len(b) > 0 {
+ *dst.offset(mi.unrecognized).toBytes() = append([]byte(nil), b...)
+ }
+ }
+}
+
+func (mi *mergeInfo) computeMergeInfo() {
+ mi.lock.Lock()
+ defer mi.lock.Unlock()
+ if mi.initialized != 0 {
+ return
+ }
+ t := mi.typ
+ n := t.NumField()
+
+ props := GetProperties(t)
+ for i := 0; i < n; i++ {
+ f := t.Field(i)
+ if strings.HasPrefix(f.Name, "XXX_") {
+ continue
+ }
+
+ mfi := mergeFieldInfo{field: toField(&f)}
+ tf := f.Type
+
+ // As an optimization, we can avoid the merge function call cost
+ // if we know for sure that the source will have no effect
+ // by checking if it is the zero value.
+ if unsafeAllowed {
+ switch tf.Kind() {
+ case reflect.Ptr, reflect.Slice, reflect.String:
+ // As a special case, we assume slices and strings are pointers
+ // since we know that the first field in the SliceSlice or
+ // StringHeader is a data pointer.
+ mfi.isPointer = true
+ case reflect.Bool:
+ mfi.basicWidth = 1
+ case reflect.Int32, reflect.Uint32, reflect.Float32:
+ mfi.basicWidth = 4
+ case reflect.Int64, reflect.Uint64, reflect.Float64:
+ mfi.basicWidth = 8
+ }
+ }
+
+ // Unwrap tf to get at its most basic type.
+ var isPointer, isSlice bool
+ if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
+ isSlice = true
+ tf = tf.Elem()
+ }
+ if tf.Kind() == reflect.Ptr {
+ isPointer = true
+ tf = tf.Elem()
+ }
+ if isPointer && isSlice && tf.Kind() != reflect.Struct {
+ panic("both pointer and slice for basic type in " + tf.Name())
+ }
+
+ switch tf.Kind() {
+ case reflect.Int32:
+ switch {
+ case isSlice: // E.g., []int32
+ mfi.merge = func(dst, src pointer) {
+ // NOTE: toInt32Slice is not defined (see pointer_reflect.go).
+ /*
+ sfsp := src.toInt32Slice()
+ if *sfsp != nil {
+ dfsp := dst.toInt32Slice()
+ *dfsp = append(*dfsp, *sfsp...)
+ if *dfsp == nil {
+ *dfsp = []int64{}
+ }
+ }
+ */
+ sfs := src.getInt32Slice()
+ if sfs != nil {
+ dfs := dst.getInt32Slice()
+ dfs = append(dfs, sfs...)
+ if dfs == nil {
+ dfs = []int32{}
+ }
+ dst.setInt32Slice(dfs)
+ }
+ }
+ case isPointer: // E.g., *int32
+ mfi.merge = func(dst, src pointer) {
+ // NOTE: toInt32Ptr is not defined (see pointer_reflect.go).
+ /*
+ sfpp := src.toInt32Ptr()
+ if *sfpp != nil {
+ dfpp := dst.toInt32Ptr()
+ if *dfpp == nil {
+ *dfpp = Int32(**sfpp)
+ } else {
+ **dfpp = **sfpp
+ }
+ }
+ */
+ sfp := src.getInt32Ptr()
+ if sfp != nil {
+ dfp := dst.getInt32Ptr()
+ if dfp == nil {
+ dst.setInt32Ptr(*sfp)
+ } else {
+ *dfp = *sfp
+ }
+ }
+ }
+ default: // E.g., int32
+ mfi.merge = func(dst, src pointer) {
+ if v := *src.toInt32(); v != 0 {
+ *dst.toInt32() = v
+ }
+ }
+ }
+ case reflect.Int64:
+ switch {
+ case isSlice: // E.g., []int64
+ mfi.merge = func(dst, src pointer) {
+ sfsp := src.toInt64Slice()
+ if *sfsp != nil {
+ dfsp := dst.toInt64Slice()
+ *dfsp = append(*dfsp, *sfsp...)
+ if *dfsp == nil {
+ *dfsp = []int64{}
+ }
+ }
+ }
+ case isPointer: // E.g., *int64
+ mfi.merge = func(dst, src pointer) {
+ sfpp := src.toInt64Ptr()
+ if *sfpp != nil {
+ dfpp := dst.toInt64Ptr()
+ if *dfpp == nil {
+ *dfpp = Int64(**sfpp)
+ } else {
+ **dfpp = **sfpp
+ }
+ }
+ }
+ default: // E.g., int64
+ mfi.merge = func(dst, src pointer) {
+ if v := *src.toInt64(); v != 0 {
+ *dst.toInt64() = v
+ }
+ }
+ }
+ case reflect.Uint32:
+ switch {
+ case isSlice: // E.g., []uint32
+ mfi.merge = func(dst, src pointer) {
+ sfsp := src.toUint32Slice()
+ if *sfsp != nil {
+ dfsp := dst.toUint32Slice()
+ *dfsp = append(*dfsp, *sfsp...)
+ if *dfsp == nil {
+ *dfsp = []uint32{}
+ }
+ }
+ }
+ case isPointer: // E.g., *uint32
+ mfi.merge = func(dst, src pointer) {
+ sfpp := src.toUint32Ptr()
+ if *sfpp != nil {
+ dfpp := dst.toUint32Ptr()
+ if *dfpp == nil {
+ *dfpp = Uint32(**sfpp)
+ } else {
+ **dfpp = **sfpp
+ }
+ }
+ }
+ default: // E.g., uint32
+ mfi.merge = func(dst, src pointer) {
+ if v := *src.toUint32(); v != 0 {
+ *dst.toUint32() = v
+ }
+ }
+ }
+ case reflect.Uint64:
+ switch {
+ case isSlice: // E.g., []uint64
+ mfi.merge = func(dst, src pointer) {
+ sfsp := src.toUint64Slice()
+ if *sfsp != nil {
+ dfsp := dst.toUint64Slice()
+ *dfsp = append(*dfsp, *sfsp...)
+ if *dfsp == nil {
+ *dfsp = []uint64{}
+ }
+ }
+ }
+ case isPointer: // E.g., *uint64
+ mfi.merge = func(dst, src pointer) {
+ sfpp := src.toUint64Ptr()
+ if *sfpp != nil {
+ dfpp := dst.toUint64Ptr()
+ if *dfpp == nil {
+ *dfpp = Uint64(**sfpp)
+ } else {
+ **dfpp = **sfpp
+ }
+ }
+ }
+ default: // E.g., uint64
+ mfi.merge = func(dst, src pointer) {
+ if v := *src.toUint64(); v != 0 {
+ *dst.toUint64() = v
+ }
+ }
+ }
+ case reflect.Float32:
+ switch {
+ case isSlice: // E.g., []float32
+ mfi.merge = func(dst, src pointer) {
+ sfsp := src.toFloat32Slice()
+ if *sfsp != nil {
+ dfsp := dst.toFloat32Slice()
+ *dfsp = append(*dfsp, *sfsp...)
+ if *dfsp == nil {
+ *dfsp = []float32{}
+ }
+ }
+ }
+ case isPointer: // E.g., *float32
+ mfi.merge = func(dst, src pointer) {
+ sfpp := src.toFloat32Ptr()
+ if *sfpp != nil {
+ dfpp := dst.toFloat32Ptr()
+ if *dfpp == nil {
+ *dfpp = Float32(**sfpp)
+ } else {
+ **dfpp = **sfpp
+ }
+ }
+ }
+ default: // E.g., float32
+ mfi.merge = func(dst, src pointer) {
+ if v := *src.toFloat32(); v != 0 {
+ *dst.toFloat32() = v
+ }
+ }
+ }
+ case reflect.Float64:
+ switch {
+ case isSlice: // E.g., []float64
+ mfi.merge = func(dst, src pointer) {
+ sfsp := src.toFloat64Slice()
+ if *sfsp != nil {
+ dfsp := dst.toFloat64Slice()
+ *dfsp = append(*dfsp, *sfsp...)
+ if *dfsp == nil {
+ *dfsp = []float64{}
+ }
+ }
+ }
+ case isPointer: // E.g., *float64
+ mfi.merge = func(dst, src pointer) {
+ sfpp := src.toFloat64Ptr()
+ if *sfpp != nil {
+ dfpp := dst.toFloat64Ptr()
+ if *dfpp == nil {
+ *dfpp = Float64(**sfpp)
+ } else {
+ **dfpp = **sfpp
+ }
+ }
+ }
+ default: // E.g., float64
+ mfi.merge = func(dst, src pointer) {
+ if v := *src.toFloat64(); v != 0 {
+ *dst.toFloat64() = v
+ }
+ }
+ }
+ case reflect.Bool:
+ switch {
+ case isSlice: // E.g., []bool
+ mfi.merge = func(dst, src pointer) {
+ sfsp := src.toBoolSlice()
+ if *sfsp != nil {
+ dfsp := dst.toBoolSlice()
+ *dfsp = append(*dfsp, *sfsp...)
+ if *dfsp == nil {
+ *dfsp = []bool{}
+ }
+ }
+ }
+ case isPointer: // E.g., *bool
+ mfi.merge = func(dst, src pointer) {
+ sfpp := src.toBoolPtr()
+ if *sfpp != nil {
+ dfpp := dst.toBoolPtr()
+ if *dfpp == nil {
+ *dfpp = Bool(**sfpp)
+ } else {
+ **dfpp = **sfpp
+ }
+ }
+ }
+ default: // E.g., bool
+ mfi.merge = func(dst, src pointer) {
+ if v := *src.toBool(); v {
+ *dst.toBool() = v
+ }
+ }
+ }
+ case reflect.String:
+ switch {
+ case isSlice: // E.g., []string
+ mfi.merge = func(dst, src pointer) {
+ sfsp := src.toStringSlice()
+ if *sfsp != nil {
+ dfsp := dst.toStringSlice()
+ *dfsp = append(*dfsp, *sfsp...)
+ if *dfsp == nil {
+ *dfsp = []string{}
+ }
+ }
+ }
+ case isPointer: // E.g., *string
+ mfi.merge = func(dst, src pointer) {
+ sfpp := src.toStringPtr()
+ if *sfpp != nil {
+ dfpp := dst.toStringPtr()
+ if *dfpp == nil {
+ *dfpp = String(**sfpp)
+ } else {
+ **dfpp = **sfpp
+ }
+ }
+ }
+ default: // E.g., string
+ mfi.merge = func(dst, src pointer) {
+ if v := *src.toString(); v != "" {
+ *dst.toString() = v
+ }
+ }
+ }
+ case reflect.Slice:
+ isProto3 := props.Prop[i].proto3
+ switch {
+ case isPointer:
+ panic("bad pointer in byte slice case in " + tf.Name())
+ case tf.Elem().Kind() != reflect.Uint8:
+ panic("bad element kind in byte slice case in " + tf.Name())
+ case isSlice: // E.g., [][]byte
+ mfi.merge = func(dst, src pointer) {
+ sbsp := src.toBytesSlice()
+ if *sbsp != nil {
+ dbsp := dst.toBytesSlice()
+ for _, sb := range *sbsp {
+ if sb == nil {
+ *dbsp = append(*dbsp, nil)
+ } else {
+ *dbsp = append(*dbsp, append([]byte{}, sb...))
+ }
+ }
+ if *dbsp == nil {
+ *dbsp = [][]byte{}
+ }
+ }
+ }
+ default: // E.g., []byte
+ mfi.merge = func(dst, src pointer) {
+ sbp := src.toBytes()
+ if *sbp != nil {
+ dbp := dst.toBytes()
+ if !isProto3 || len(*sbp) > 0 {
+ *dbp = append([]byte{}, *sbp...)
+ }
+ }
+ }
+ }
+ case reflect.Struct:
+ switch {
+ case !isPointer:
+ panic(fmt.Sprintf("message field %s without pointer", tf))
+ case isSlice: // E.g., []*pb.T
+ mi := getMergeInfo(tf)
+ mfi.merge = func(dst, src pointer) {
+ sps := src.getPointerSlice()
+ if sps != nil {
+ dps := dst.getPointerSlice()
+ for _, sp := range sps {
+ var dp pointer
+ if !sp.isNil() {
+ dp = valToPointer(reflect.New(tf))
+ mi.merge(dp, sp)
+ }
+ dps = append(dps, dp)
+ }
+ if dps == nil {
+ dps = []pointer{}
+ }
+ dst.setPointerSlice(dps)
+ }
+ }
+ default: // E.g., *pb.T
+ mi := getMergeInfo(tf)
+ mfi.merge = func(dst, src pointer) {
+ sp := src.getPointer()
+ if !sp.isNil() {
+ dp := dst.getPointer()
+ if dp.isNil() {
+ dp = valToPointer(reflect.New(tf))
+ dst.setPointer(dp)
+ }
+ mi.merge(dp, sp)
+ }
+ }
+ }
+ case reflect.Map:
+ switch {
+ case isPointer || isSlice:
+ panic("bad pointer or slice in map case in " + tf.Name())
+ default: // E.g., map[K]V
+ mfi.merge = func(dst, src pointer) {
+ sm := src.asPointerTo(tf).Elem()
+ if sm.Len() == 0 {
+ return
+ }
+ dm := dst.asPointerTo(tf).Elem()
+ if dm.IsNil() {
+ dm.Set(reflect.MakeMap(tf))
+ }
+
+ switch tf.Elem().Kind() {
+ case reflect.Ptr: // Proto struct (e.g., *T)
+ for _, key := range sm.MapKeys() {
+ val := sm.MapIndex(key)
+ val = reflect.ValueOf(Clone(val.Interface().(Message)))
+ dm.SetMapIndex(key, val)
+ }
+ case reflect.Slice: // E.g. Bytes type (e.g., []byte)
+ for _, key := range sm.MapKeys() {
+ val := sm.MapIndex(key)
+ val = reflect.ValueOf(append([]byte{}, val.Bytes()...))
+ dm.SetMapIndex(key, val)
+ }
+ default: // Basic type (e.g., string)
+ for _, key := range sm.MapKeys() {
+ val := sm.MapIndex(key)
+ dm.SetMapIndex(key, val)
+ }
+ }
+ }
+ }
+ case reflect.Interface:
+ // Must be oneof field.
+ switch {
+ case isPointer || isSlice:
+ panic("bad pointer or slice in interface case in " + tf.Name())
+ default: // E.g., interface{}
+ // TODO: Make this faster?
+ mfi.merge = func(dst, src pointer) {
+ su := src.asPointerTo(tf).Elem()
+ if !su.IsNil() {
+ du := dst.asPointerTo(tf).Elem()
+ typ := su.Elem().Type()
+ if du.IsNil() || du.Elem().Type() != typ {
+ du.Set(reflect.New(typ.Elem())) // Initialize interface if empty
+ }
+ sv := su.Elem().Elem().Field(0)
+ if sv.Kind() == reflect.Ptr && sv.IsNil() {
+ return
+ }
+ dv := du.Elem().Elem().Field(0)
+ if dv.Kind() == reflect.Ptr && dv.IsNil() {
+ dv.Set(reflect.New(sv.Type().Elem())) // Initialize proto message if empty
+ }
+ switch sv.Type().Kind() {
+ case reflect.Ptr: // Proto struct (e.g., *T)
+ Merge(dv.Interface().(Message), sv.Interface().(Message))
+ case reflect.Slice: // E.g. Bytes type (e.g., []byte)
+ dv.Set(reflect.ValueOf(append([]byte{}, sv.Bytes()...)))
+ default: // Basic type (e.g., string)
+ dv.Set(sv)
+ }
+ }
+ }
+ }
+ default:
+ panic(fmt.Sprintf("merger not found for type:%s", tf))
+ }
+ mi.fields = append(mi.fields, mfi)
+ }
+
+ mi.unrecognized = invalidField
+ if f, ok := t.FieldByName("XXX_unrecognized"); ok {
+ if f.Type != reflect.TypeOf([]byte{}) {
+ panic("expected XXX_unrecognized to be of type []byte")
+ }
+ mi.unrecognized = toField(&f)
+ }
+
+ atomic.StoreInt32(&mi.initialized, 1)
+}
diff --git a/vendor/github.com/golang/protobuf/proto/table_unmarshal.go b/vendor/github.com/golang/protobuf/proto/table_unmarshal.go
new file mode 100644
index 000000000..acee2fc52
--- /dev/null
+++ b/vendor/github.com/golang/protobuf/proto/table_unmarshal.go
@@ -0,0 +1,2053 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2016 The Go Authors. All rights reserved.
+// https://github.com/golang/protobuf
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "unicode/utf8"
+)
+
+// Unmarshal is the entry point from the generated .pb.go files.
+// This function is not intended to be used by non-generated code.
+// This function is not subject to any compatibility guarantee.
+// msg contains a pointer to a protocol buffer struct.
+// b is the data to be unmarshaled into the protocol buffer.
+// a is a pointer to a place to store cached unmarshal information.
+func (a *InternalMessageInfo) Unmarshal(msg Message, b []byte) error {
+ // Load the unmarshal information for this message type.
+ // The atomic load ensures memory consistency.
+ u := atomicLoadUnmarshalInfo(&a.unmarshal)
+ if u == nil {
+ // Slow path: find unmarshal info for msg, update a with it.
+ u = getUnmarshalInfo(reflect.TypeOf(msg).Elem())
+ atomicStoreUnmarshalInfo(&a.unmarshal, u)
+ }
+ // Then do the unmarshaling.
+ err := u.unmarshal(toPointer(&msg), b)
+ return err
+}
+
+type unmarshalInfo struct {
+ typ reflect.Type // type of the protobuf struct
+
+ // 0 = only typ field is initialized
+ // 1 = completely initialized
+ initialized int32
+ lock sync.Mutex // prevents double initialization
+ dense []unmarshalFieldInfo // fields indexed by tag #
+ sparse map[uint64]unmarshalFieldInfo // fields indexed by tag #
+ reqFields []string // names of required fields
+ reqMask uint64 // 1<<len(reqFields)-1
+ unrecognized field // offset of []byte to put unrecognized data (or invalidField if we should throw it away)
+ extensions field // offset of extensions field (of type proto.XXX_InternalExtensions), or invalidField if it does not exist
+ oldExtensions field // offset of old-form extensions field (of type map[int]Extension)
+ extensionRanges []ExtensionRange // if non-nil, implies extensions field is valid
+ isMessageSet bool // if true, implies extensions field is valid
+}
+
+// An unmarshaler takes a stream of bytes and a pointer to a field of a message.
+// It decodes the field, stores it at f, and returns the unused bytes.
+// w is the wire encoding.
+// b is the data after the tag and wire encoding have been read.
+type unmarshaler func(b []byte, f pointer, w int) ([]byte, error)
+
+type unmarshalFieldInfo struct {
+ // location of the field in the proto message structure.
+ field field
+
+ // function to unmarshal the data for the field.
+ unmarshal unmarshaler
+
+ // if a required field, contains a single set bit at this field's index in the required field list.
+ reqMask uint64
+
+ name string // name of the field, for error reporting
+}
+
+var (
+ unmarshalInfoMap = map[reflect.Type]*unmarshalInfo{}
+ unmarshalInfoLock sync.Mutex
+)
+
+// getUnmarshalInfo returns the data structure which can be
+// subsequently used to unmarshal a message of the given type.
+// t is the type of the message (note: not pointer to message).
+func getUnmarshalInfo(t reflect.Type) *unmarshalInfo {
+ // It would be correct to return a new unmarshalInfo
+ // unconditionally. We would end up allocating one
+ // per occurrence of that type as a message or submessage.
+ // We use a cache here just to reduce memory usage.
+ unmarshalInfoLock.Lock()
+ defer unmarshalInfoLock.Unlock()
+ u := unmarshalInfoMap[t]
+ if u == nil {
+ u = &unmarshalInfo{typ: t}
+ // Note: we just set the type here. The rest of the fields
+ // will be initialized on first use.
+ unmarshalInfoMap[t] = u
+ }
+ return u
+}
+
+// unmarshal does the main work of unmarshaling a message.
+// u provides type information used to unmarshal the message.
+// m is a pointer to a protocol buffer message.
+// b is a byte stream to unmarshal into m.
+// This is top routine used when recursively unmarshaling submessages.
+func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
+ if atomic.LoadInt32(&u.initialized) == 0 {
+ u.computeUnmarshalInfo()
+ }
+ if u.isMessageSet {
+ return unmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
+ }
+ var reqMask uint64 // bitmask of required fields we've seen.
+ var errLater error
+ for len(b) > 0 {
+ // Read tag and wire type.
+ // Special case 1 and 2 byte varints.
+ var x uint64
+ if b[0] < 128 {
+ x = uint64(b[0])
+ b = b[1:]
+ } else if len(b) >= 2 && b[1] < 128 {
+ x = uint64(b[0]&0x7f) + uint64(b[1])<<7
+ b = b[2:]
+ } else {
+ var n int
+ x, n = decodeVarint(b)
+ if n == 0 {
+ return io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ }
+ tag := x >> 3
+ wire := int(x) & 7
+
+ // Dispatch on the tag to one of the unmarshal* functions below.
+ var f unmarshalFieldInfo
+ if tag < uint64(len(u.dense)) {
+ f = u.dense[tag]
+ } else {
+ f = u.sparse[tag]
+ }
+ if fn := f.unmarshal; fn != nil {
+ var err error
+ b, err = fn(b, m.offset(f.field), wire)
+ if err == nil {
+ reqMask |= f.reqMask
+ continue
+ }
+ if r, ok := err.(*RequiredNotSetError); ok {
+ // Remember this error, but keep parsing. We need to produce
+ // a full parse even if a required field is missing.
+ if errLater == nil {
+ errLater = r
+ }
+ reqMask |= f.reqMask
+ continue
+ }
+ if err != errInternalBadWireType {
+ if err == errInvalidUTF8 {
+ if errLater == nil {
+ fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name
+ errLater = &invalidUTF8Error{fullName}
+ }
+ continue
+ }
+ return err
+ }
+ // Fragments with bad wire type are treated as unknown fields.
+ }
+
+ // Unknown tag.
+ if !u.unrecognized.IsValid() {
+ // Don't keep unrecognized data; just skip it.
+ var err error
+ b, err = skipField(b, wire)
+ if err != nil {
+ return err
+ }
+ continue
+ }
+ // Keep unrecognized data around.
+ // maybe in extensions, maybe in the unrecognized field.
+ z := m.offset(u.unrecognized).toBytes()
+ var emap map[int32]Extension
+ var e Extension
+ for _, r := range u.extensionRanges {
+ if uint64(r.Start) <= tag && tag <= uint64(r.End) {
+ if u.extensions.IsValid() {
+ mp := m.offset(u.extensions).toExtensions()
+ emap = mp.extensionsWrite()
+ e = emap[int32(tag)]
+ z = &e.enc
+ break
+ }
+ if u.oldExtensions.IsValid() {
+ p := m.offset(u.oldExtensions).toOldExtensions()
+ emap = *p
+ if emap == nil {
+ emap = map[int32]Extension{}
+ *p = emap
+ }
+ e = emap[int32(tag)]
+ z = &e.enc
+ break
+ }
+ panic("no extensions field available")
+ }
+ }
+
+ // Use wire type to skip data.
+ var err error
+ b0 := b
+ b, err = skipField(b, wire)
+ if err != nil {
+ return err
+ }
+ *z = encodeVarint(*z, tag<<3|uint64(wire))
+ *z = append(*z, b0[:len(b0)-len(b)]...)
+
+ if emap != nil {
+ emap[int32(tag)] = e
+ }
+ }
+ if reqMask != u.reqMask && errLater == nil {
+ // A required field of this message is missing.
+ for _, n := range u.reqFields {
+ if reqMask&1 == 0 {
+ errLater = &RequiredNotSetError{n}
+ }
+ reqMask >>= 1
+ }
+ }
+ return errLater
+}
+
+// computeUnmarshalInfo fills in u with information for use
+// in unmarshaling protocol buffers of type u.typ.
+func (u *unmarshalInfo) computeUnmarshalInfo() {
+ u.lock.Lock()
+ defer u.lock.Unlock()
+ if u.initialized != 0 {
+ return
+ }
+ t := u.typ
+ n := t.NumField()
+
+ // Set up the "not found" value for the unrecognized byte buffer.
+ // This is the default for proto3.
+ u.unrecognized = invalidField
+ u.extensions = invalidField
+ u.oldExtensions = invalidField
+
+ // List of the generated type and offset for each oneof field.
+ type oneofField struct {
+ ityp reflect.Type // interface type of oneof field
+ field field // offset in containing message
+ }
+ var oneofFields []oneofField
+
+ for i := 0; i < n; i++ {
+ f := t.Field(i)
+ if f.Name == "XXX_unrecognized" {
+ // The byte slice used to hold unrecognized input is special.
+ if f.Type != reflect.TypeOf(([]byte)(nil)) {
+ panic("bad type for XXX_unrecognized field: " + f.Type.Name())
+ }
+ u.unrecognized = toField(&f)
+ continue
+ }
+ if f.Name == "XXX_InternalExtensions" {
+ // Ditto here.
+ if f.Type != reflect.TypeOf(XXX_InternalExtensions{}) {
+ panic("bad type for XXX_InternalExtensions field: " + f.Type.Name())
+ }
+ u.extensions = toField(&f)
+ if f.Tag.Get("protobuf_messageset") == "1" {
+ u.isMessageSet = true
+ }
+ continue
+ }
+ if f.Name == "XXX_extensions" {
+ // An older form of the extensions field.
+ if f.Type != reflect.TypeOf((map[int32]Extension)(nil)) {
+ panic("bad type for XXX_extensions field: " + f.Type.Name())
+ }
+ u.oldExtensions = toField(&f)
+ continue
+ }
+ if f.Name == "XXX_NoUnkeyedLiteral" || f.Name == "XXX_sizecache" {
+ continue
+ }
+
+ oneof := f.Tag.Get("protobuf_oneof")
+ if oneof != "" {
+ oneofFields = append(oneofFields, oneofField{f.Type, toField(&f)})
+ // The rest of oneof processing happens below.
+ continue
+ }
+
+ tags := f.Tag.Get("protobuf")
+ tagArray := strings.Split(tags, ",")
+ if len(tagArray) < 2 {
+ panic("protobuf tag not enough fields in " + t.Name() + "." + f.Name + ": " + tags)
+ }
+ tag, err := strconv.Atoi(tagArray[1])
+ if err != nil {
+ panic("protobuf tag field not an integer: " + tagArray[1])
+ }
+
+ name := ""
+ for _, tag := range tagArray[3:] {
+ if strings.HasPrefix(tag, "name=") {
+ name = tag[5:]
+ }
+ }
+
+ // Extract unmarshaling function from the field (its type and tags).
+ unmarshal := fieldUnmarshaler(&f)
+
+ // Required field?
+ var reqMask uint64
+ if tagArray[2] == "req" {
+ bit := len(u.reqFields)
+ u.reqFields = append(u.reqFields, name)
+ reqMask = uint64(1) << uint(bit)
+ // TODO: if we have more than 64 required fields, we end up
+ // not verifying that all required fields are present.
+ // Fix this, perhaps using a count of required fields?
+ }
+
+ // Store the info in the correct slot in the message.
+ u.setTag(tag, toField(&f), unmarshal, reqMask, name)
+ }
+
+ // Find any types associated with oneof fields.
+ var oneofImplementers []interface{}
+ switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) {
+ case oneofFuncsIface:
+ _, _, _, oneofImplementers = m.XXX_OneofFuncs()
+ case oneofWrappersIface:
+ oneofImplementers = m.XXX_OneofWrappers()
+ }
+ for _, v := range oneofImplementers {
+ tptr := reflect.TypeOf(v) // *Msg_X
+ typ := tptr.Elem() // Msg_X
+
+ f := typ.Field(0) // oneof implementers have one field
+ baseUnmarshal := fieldUnmarshaler(&f)
+ tags := strings.Split(f.Tag.Get("protobuf"), ",")
+ fieldNum, err := strconv.Atoi(tags[1])
+ if err != nil {
+ panic("protobuf tag field not an integer: " + tags[1])
+ }
+ var name string
+ for _, tag := range tags {
+ if strings.HasPrefix(tag, "name=") {
+ name = strings.TrimPrefix(tag, "name=")
+ break
+ }
+ }
+
+ // Find the oneof field that this struct implements.
+ // Might take O(n^2) to process all of the oneofs, but who cares.
+ for _, of := range oneofFields {
+ if tptr.Implements(of.ityp) {
+ // We have found the corresponding interface for this struct.
+ // That lets us know where this struct should be stored
+ // when we encounter it during unmarshaling.
+ unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal)
+ u.setTag(fieldNum, of.field, unmarshal, 0, name)
+ }
+ }
+
+ }
+
+ // Get extension ranges, if any.
+ fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray")
+ if fn.IsValid() {
+ if !u.extensions.IsValid() && !u.oldExtensions.IsValid() {
+ panic("a message with extensions, but no extensions field in " + t.Name())
+ }
+ u.extensionRanges = fn.Call(nil)[0].Interface().([]ExtensionRange)
+ }
+
+ // Explicitly disallow tag 0. This will ensure we flag an error
+ // when decoding a buffer of all zeros. Without this code, we
+ // would decode and skip an all-zero buffer of even length.
+ // [0 0] is [tag=0/wiretype=varint varint-encoded-0].
+ u.setTag(0, zeroField, func(b []byte, f pointer, w int) ([]byte, error) {
+ return nil, fmt.Errorf("proto: %s: illegal tag 0 (wire type %d)", t, w)
+ }, 0, "")
+
+ // Set mask for required field check.
+ u.reqMask = uint64(1)<<uint(len(u.reqFields)) - 1
+
+ atomic.StoreInt32(&u.initialized, 1)
+}
+
+// setTag stores the unmarshal information for the given tag.
+// tag = tag # for field
+// field/unmarshal = unmarshal info for that field.
+// reqMask = if required, bitmask for field position in required field list. 0 otherwise.
+// name = short name of the field.
+func (u *unmarshalInfo) setTag(tag int, field field, unmarshal unmarshaler, reqMask uint64, name string) {
+ i := unmarshalFieldInfo{field: field, unmarshal: unmarshal, reqMask: reqMask, name: name}
+ n := u.typ.NumField()
+ if tag >= 0 && (tag < 16 || tag < 2*n) { // TODO: what are the right numbers here?
+ for len(u.dense) <= tag {
+ u.dense = append(u.dense, unmarshalFieldInfo{})
+ }
+ u.dense[tag] = i
+ return
+ }
+ if u.sparse == nil {
+ u.sparse = map[uint64]unmarshalFieldInfo{}
+ }
+ u.sparse[uint64(tag)] = i
+}
+
+// fieldUnmarshaler returns an unmarshaler for the given field.
+func fieldUnmarshaler(f *reflect.StructField) unmarshaler {
+ if f.Type.Kind() == reflect.Map {
+ return makeUnmarshalMap(f)
+ }
+ return typeUnmarshaler(f.Type, f.Tag.Get("protobuf"))
+}
+
+// typeUnmarshaler returns an unmarshaler for the given field type / field tag pair.
+func typeUnmarshaler(t reflect.Type, tags string) unmarshaler {
+ tagArray := strings.Split(tags, ",")
+ encoding := tagArray[0]
+ name := "unknown"
+ proto3 := false
+ validateUTF8 := true
+ for _, tag := range tagArray[3:] {
+ if strings.HasPrefix(tag, "name=") {
+ name = tag[5:]
+ }
+ if tag == "proto3" {
+ proto3 = true
+ }
+ }
+ validateUTF8 = validateUTF8 && proto3
+
+ // Figure out packaging (pointer, slice, or both)
+ slice := false
+ pointer := false
+ if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 {
+ slice = true
+ t = t.Elem()
+ }
+ if t.Kind() == reflect.Ptr {
+ pointer = true
+ t = t.Elem()
+ }
+
+ // We'll never have both pointer and slice for basic types.
+ if pointer && slice && t.Kind() != reflect.Struct {
+ panic("both pointer and slice for basic type in " + t.Name())
+ }
+
+ switch t.Kind() {
+ case reflect.Bool:
+ if pointer {
+ return unmarshalBoolPtr
+ }
+ if slice {
+ return unmarshalBoolSlice
+ }
+ return unmarshalBoolValue
+ case reflect.Int32:
+ switch encoding {
+ case "fixed32":
+ if pointer {
+ return unmarshalFixedS32Ptr
+ }
+ if slice {
+ return unmarshalFixedS32Slice
+ }
+ return unmarshalFixedS32Value
+ case "varint":
+ // this could be int32 or enum
+ if pointer {
+ return unmarshalInt32Ptr
+ }
+ if slice {
+ return unmarshalInt32Slice
+ }
+ return unmarshalInt32Value
+ case "zigzag32":
+ if pointer {
+ return unmarshalSint32Ptr
+ }
+ if slice {
+ return unmarshalSint32Slice
+ }
+ return unmarshalSint32Value
+ }
+ case reflect.Int64:
+ switch encoding {
+ case "fixed64":
+ if pointer {
+ return unmarshalFixedS64Ptr
+ }
+ if slice {
+ return unmarshalFixedS64Slice
+ }
+ return unmarshalFixedS64Value
+ case "varint":
+ if pointer {
+ return unmarshalInt64Ptr
+ }
+ if slice {
+ return unmarshalInt64Slice
+ }
+ return unmarshalInt64Value
+ case "zigzag64":
+ if pointer {
+ return unmarshalSint64Ptr
+ }
+ if slice {
+ return unmarshalSint64Slice
+ }
+ return unmarshalSint64Value
+ }
+ case reflect.Uint32:
+ switch encoding {
+ case "fixed32":
+ if pointer {
+ return unmarshalFixed32Ptr
+ }
+ if slice {
+ return unmarshalFixed32Slice
+ }
+ return unmarshalFixed32Value
+ case "varint":
+ if pointer {
+ return unmarshalUint32Ptr
+ }
+ if slice {
+ return unmarshalUint32Slice
+ }
+ return unmarshalUint32Value
+ }
+ case reflect.Uint64:
+ switch encoding {
+ case "fixed64":
+ if pointer {
+ return unmarshalFixed64Ptr
+ }
+ if slice {
+ return unmarshalFixed64Slice
+ }
+ return unmarshalFixed64Value
+ case "varint":
+ if pointer {
+ return unmarshalUint64Ptr
+ }
+ if slice {
+ return unmarshalUint64Slice
+ }
+ return unmarshalUint64Value
+ }
+ case reflect.Float32:
+ if pointer {
+ return unmarshalFloat32Ptr
+ }
+ if slice {
+ return unmarshalFloat32Slice
+ }
+ return unmarshalFloat32Value
+ case reflect.Float64:
+ if pointer {
+ return unmarshalFloat64Ptr
+ }
+ if slice {
+ return unmarshalFloat64Slice
+ }
+ return unmarshalFloat64Value
+ case reflect.Map:
+ panic("map type in typeUnmarshaler in " + t.Name())
+ case reflect.Slice:
+ if pointer {
+ panic("bad pointer in slice case in " + t.Name())
+ }
+ if slice {
+ return unmarshalBytesSlice
+ }
+ return unmarshalBytesValue
+ case reflect.String:
+ if validateUTF8 {
+ if pointer {
+ return unmarshalUTF8StringPtr
+ }
+ if slice {
+ return unmarshalUTF8StringSlice
+ }
+ return unmarshalUTF8StringValue
+ }
+ if pointer {
+ return unmarshalStringPtr
+ }
+ if slice {
+ return unmarshalStringSlice
+ }
+ return unmarshalStringValue
+ case reflect.Struct:
+ // message or group field
+ if !pointer {
+ panic(fmt.Sprintf("message/group field %s:%s without pointer", t, encoding))
+ }
+ switch encoding {
+ case "bytes":
+ if slice {
+ return makeUnmarshalMessageSlicePtr(getUnmarshalInfo(t), name)
+ }
+ return makeUnmarshalMessagePtr(getUnmarshalInfo(t), name)
+ case "group":
+ if slice {
+ return makeUnmarshalGroupSlicePtr(getUnmarshalInfo(t), name)
+ }
+ return makeUnmarshalGroupPtr(getUnmarshalInfo(t), name)
+ }
+ }
+ panic(fmt.Sprintf("unmarshaler not found type:%s encoding:%s", t, encoding))
+}
+
+// Below are all the unmarshalers for individual fields of various types.
+
+func unmarshalInt64Value(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int64(x)
+ *f.toInt64() = v
+ return b, nil
+}
+
+func unmarshalInt64Ptr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int64(x)
+ *f.toInt64Ptr() = &v
+ return b, nil
+}
+
+func unmarshalInt64Slice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ x, n = decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int64(x)
+ s := f.toInt64Slice()
+ *s = append(*s, v)
+ }
+ return res, nil
+ }
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int64(x)
+ s := f.toInt64Slice()
+ *s = append(*s, v)
+ return b, nil
+}
+
+func unmarshalSint64Value(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int64(x>>1) ^ int64(x)<<63>>63
+ *f.toInt64() = v
+ return b, nil
+}
+
+func unmarshalSint64Ptr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int64(x>>1) ^ int64(x)<<63>>63
+ *f.toInt64Ptr() = &v
+ return b, nil
+}
+
+func unmarshalSint64Slice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ x, n = decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int64(x>>1) ^ int64(x)<<63>>63
+ s := f.toInt64Slice()
+ *s = append(*s, v)
+ }
+ return res, nil
+ }
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int64(x>>1) ^ int64(x)<<63>>63
+ s := f.toInt64Slice()
+ *s = append(*s, v)
+ return b, nil
+}
+
+func unmarshalUint64Value(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := uint64(x)
+ *f.toUint64() = v
+ return b, nil
+}
+
+func unmarshalUint64Ptr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := uint64(x)
+ *f.toUint64Ptr() = &v
+ return b, nil
+}
+
+func unmarshalUint64Slice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ x, n = decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := uint64(x)
+ s := f.toUint64Slice()
+ *s = append(*s, v)
+ }
+ return res, nil
+ }
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := uint64(x)
+ s := f.toUint64Slice()
+ *s = append(*s, v)
+ return b, nil
+}
+
+func unmarshalInt32Value(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int32(x)
+ *f.toInt32() = v
+ return b, nil
+}
+
+func unmarshalInt32Ptr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int32(x)
+ f.setInt32Ptr(v)
+ return b, nil
+}
+
+func unmarshalInt32Slice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ x, n = decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int32(x)
+ f.appendInt32Slice(v)
+ }
+ return res, nil
+ }
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int32(x)
+ f.appendInt32Slice(v)
+ return b, nil
+}
+
+func unmarshalSint32Value(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int32(x>>1) ^ int32(x)<<31>>31
+ *f.toInt32() = v
+ return b, nil
+}
+
+func unmarshalSint32Ptr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int32(x>>1) ^ int32(x)<<31>>31
+ f.setInt32Ptr(v)
+ return b, nil
+}
+
+func unmarshalSint32Slice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ x, n = decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int32(x>>1) ^ int32(x)<<31>>31
+ f.appendInt32Slice(v)
+ }
+ return res, nil
+ }
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := int32(x>>1) ^ int32(x)<<31>>31
+ f.appendInt32Slice(v)
+ return b, nil
+}
+
+func unmarshalUint32Value(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := uint32(x)
+ *f.toUint32() = v
+ return b, nil
+}
+
+func unmarshalUint32Ptr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := uint32(x)
+ *f.toUint32Ptr() = &v
+ return b, nil
+}
+
+func unmarshalUint32Slice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ x, n = decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := uint32(x)
+ s := f.toUint32Slice()
+ *s = append(*s, v)
+ }
+ return res, nil
+ }
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ v := uint32(x)
+ s := f.toUint32Slice()
+ *s = append(*s, v)
+ return b, nil
+}
+
+func unmarshalFixed64Value(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireFixed64 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 8 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+ *f.toUint64() = v
+ return b[8:], nil
+}
+
+func unmarshalFixed64Ptr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireFixed64 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 8 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+ *f.toUint64Ptr() = &v
+ return b[8:], nil
+}
+
+func unmarshalFixed64Slice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ if len(b) < 8 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+ s := f.toUint64Slice()
+ *s = append(*s, v)
+ b = b[8:]
+ }
+ return res, nil
+ }
+ if w != WireFixed64 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 8 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+ s := f.toUint64Slice()
+ *s = append(*s, v)
+ return b[8:], nil
+}
+
+func unmarshalFixedS64Value(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireFixed64 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 8 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56
+ *f.toInt64() = v
+ return b[8:], nil
+}
+
+func unmarshalFixedS64Ptr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireFixed64 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 8 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56
+ *f.toInt64Ptr() = &v
+ return b[8:], nil
+}
+
+func unmarshalFixedS64Slice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ if len(b) < 8 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56
+ s := f.toInt64Slice()
+ *s = append(*s, v)
+ b = b[8:]
+ }
+ return res, nil
+ }
+ if w != WireFixed64 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 8 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56
+ s := f.toInt64Slice()
+ *s = append(*s, v)
+ return b[8:], nil
+}
+
+func unmarshalFixed32Value(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireFixed32 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+ *f.toUint32() = v
+ return b[4:], nil
+}
+
+func unmarshalFixed32Ptr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireFixed32 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+ *f.toUint32Ptr() = &v
+ return b[4:], nil
+}
+
+func unmarshalFixed32Slice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ if len(b) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+ s := f.toUint32Slice()
+ *s = append(*s, v)
+ b = b[4:]
+ }
+ return res, nil
+ }
+ if w != WireFixed32 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+ s := f.toUint32Slice()
+ *s = append(*s, v)
+ return b[4:], nil
+}
+
+func unmarshalFixedS32Value(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireFixed32 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24
+ *f.toInt32() = v
+ return b[4:], nil
+}
+
+func unmarshalFixedS32Ptr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireFixed32 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24
+ f.setInt32Ptr(v)
+ return b[4:], nil
+}
+
+func unmarshalFixedS32Slice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ if len(b) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24
+ f.appendInt32Slice(v)
+ b = b[4:]
+ }
+ return res, nil
+ }
+ if w != WireFixed32 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24
+ f.appendInt32Slice(v)
+ return b[4:], nil
+}
+
+func unmarshalBoolValue(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ // Note: any length varint is allowed, even though any sane
+ // encoder will use one byte.
+ // See https://github.com/golang/protobuf/issues/76
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ // TODO: check if x>1? Tests seem to indicate no.
+ v := x != 0
+ *f.toBool() = v
+ return b[n:], nil
+}
+
+func unmarshalBoolPtr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := x != 0
+ *f.toBoolPtr() = &v
+ return b[n:], nil
+}
+
+func unmarshalBoolSlice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ x, n = decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := x != 0
+ s := f.toBoolSlice()
+ *s = append(*s, v)
+ b = b[n:]
+ }
+ return res, nil
+ }
+ if w != WireVarint {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := x != 0
+ s := f.toBoolSlice()
+ *s = append(*s, v)
+ return b[n:], nil
+}
+
+func unmarshalFloat64Value(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireFixed64 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 8 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56)
+ *f.toFloat64() = v
+ return b[8:], nil
+}
+
+func unmarshalFloat64Ptr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireFixed64 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 8 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56)
+ *f.toFloat64Ptr() = &v
+ return b[8:], nil
+}
+
+func unmarshalFloat64Slice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ if len(b) < 8 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56)
+ s := f.toFloat64Slice()
+ *s = append(*s, v)
+ b = b[8:]
+ }
+ return res, nil
+ }
+ if w != WireFixed64 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 8 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56)
+ s := f.toFloat64Slice()
+ *s = append(*s, v)
+ return b[8:], nil
+}
+
+func unmarshalFloat32Value(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireFixed32 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24)
+ *f.toFloat32() = v
+ return b[4:], nil
+}
+
+func unmarshalFloat32Ptr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireFixed32 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24)
+ *f.toFloat32Ptr() = &v
+ return b[4:], nil
+}
+
+func unmarshalFloat32Slice(b []byte, f pointer, w int) ([]byte, error) {
+ if w == WireBytes { // packed
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ res := b[x:]
+ b = b[:x]
+ for len(b) > 0 {
+ if len(b) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24)
+ s := f.toFloat32Slice()
+ *s = append(*s, v)
+ b = b[4:]
+ }
+ return res, nil
+ }
+ if w != WireFixed32 {
+ return b, errInternalBadWireType
+ }
+ if len(b) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24)
+ s := f.toFloat32Slice()
+ *s = append(*s, v)
+ return b[4:], nil
+}
+
+func unmarshalStringValue(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireBytes {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := string(b[:x])
+ *f.toString() = v
+ return b[x:], nil
+}
+
+func unmarshalStringPtr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireBytes {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := string(b[:x])
+ *f.toStringPtr() = &v
+ return b[x:], nil
+}
+
+func unmarshalStringSlice(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireBytes {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := string(b[:x])
+ s := f.toStringSlice()
+ *s = append(*s, v)
+ return b[x:], nil
+}
+
+func unmarshalUTF8StringValue(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireBytes {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := string(b[:x])
+ *f.toString() = v
+ if !utf8.ValidString(v) {
+ return b[x:], errInvalidUTF8
+ }
+ return b[x:], nil
+}
+
+func unmarshalUTF8StringPtr(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireBytes {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := string(b[:x])
+ *f.toStringPtr() = &v
+ if !utf8.ValidString(v) {
+ return b[x:], errInvalidUTF8
+ }
+ return b[x:], nil
+}
+
+func unmarshalUTF8StringSlice(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireBytes {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := string(b[:x])
+ s := f.toStringSlice()
+ *s = append(*s, v)
+ if !utf8.ValidString(v) {
+ return b[x:], errInvalidUTF8
+ }
+ return b[x:], nil
+}
+
+var emptyBuf [0]byte
+
+func unmarshalBytesValue(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireBytes {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ // The use of append here is a trick which avoids the zeroing
+ // that would be required if we used a make/copy pair.
+ // We append to emptyBuf instead of nil because we want
+ // a non-nil result even when the length is 0.
+ v := append(emptyBuf[:], b[:x]...)
+ *f.toBytes() = v
+ return b[x:], nil
+}
+
+func unmarshalBytesSlice(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireBytes {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := append(emptyBuf[:], b[:x]...)
+ s := f.toBytesSlice()
+ *s = append(*s, v)
+ return b[x:], nil
+}
+
+func makeUnmarshalMessagePtr(sub *unmarshalInfo, name string) unmarshaler {
+ return func(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireBytes {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ // First read the message field to see if something is there.
+ // The semantics of multiple submessages are weird. Instead of
+ // the last one winning (as it is for all other fields), multiple
+ // submessages are merged.
+ v := f.getPointer()
+ if v.isNil() {
+ v = valToPointer(reflect.New(sub.typ))
+ f.setPointer(v)
+ }
+ err := sub.unmarshal(v, b[:x])
+ if err != nil {
+ if r, ok := err.(*RequiredNotSetError); ok {
+ r.field = name + "." + r.field
+ } else {
+ return nil, err
+ }
+ }
+ return b[x:], err
+ }
+}
+
+func makeUnmarshalMessageSlicePtr(sub *unmarshalInfo, name string) unmarshaler {
+ return func(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireBytes {
+ return b, errInternalBadWireType
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := valToPointer(reflect.New(sub.typ))
+ err := sub.unmarshal(v, b[:x])
+ if err != nil {
+ if r, ok := err.(*RequiredNotSetError); ok {
+ r.field = name + "." + r.field
+ } else {
+ return nil, err
+ }
+ }
+ f.appendPointer(v)
+ return b[x:], err
+ }
+}
+
+func makeUnmarshalGroupPtr(sub *unmarshalInfo, name string) unmarshaler {
+ return func(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireStartGroup {
+ return b, errInternalBadWireType
+ }
+ x, y := findEndGroup(b)
+ if x < 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := f.getPointer()
+ if v.isNil() {
+ v = valToPointer(reflect.New(sub.typ))
+ f.setPointer(v)
+ }
+ err := sub.unmarshal(v, b[:x])
+ if err != nil {
+ if r, ok := err.(*RequiredNotSetError); ok {
+ r.field = name + "." + r.field
+ } else {
+ return nil, err
+ }
+ }
+ return b[y:], err
+ }
+}
+
+func makeUnmarshalGroupSlicePtr(sub *unmarshalInfo, name string) unmarshaler {
+ return func(b []byte, f pointer, w int) ([]byte, error) {
+ if w != WireStartGroup {
+ return b, errInternalBadWireType
+ }
+ x, y := findEndGroup(b)
+ if x < 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ v := valToPointer(reflect.New(sub.typ))
+ err := sub.unmarshal(v, b[:x])
+ if err != nil {
+ if r, ok := err.(*RequiredNotSetError); ok {
+ r.field = name + "." + r.field
+ } else {
+ return nil, err
+ }
+ }
+ f.appendPointer(v)
+ return b[y:], err
+ }
+}
+
+func makeUnmarshalMap(f *reflect.StructField) unmarshaler {
+ t := f.Type
+ kt := t.Key()
+ vt := t.Elem()
+ unmarshalKey := typeUnmarshaler(kt, f.Tag.Get("protobuf_key"))
+ unmarshalVal := typeUnmarshaler(vt, f.Tag.Get("protobuf_val"))
+ return func(b []byte, f pointer, w int) ([]byte, error) {
+ // The map entry is a submessage. Figure out how big it is.
+ if w != WireBytes {
+ return nil, fmt.Errorf("proto: bad wiretype for map field: got %d want %d", w, WireBytes)
+ }
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b = b[n:]
+ if x > uint64(len(b)) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ r := b[x:] // unused data to return
+ b = b[:x] // data for map entry
+
+ // Note: we could use #keys * #values ~= 200 functions
+ // to do map decoding without reflection. Probably not worth it.
+ // Maps will be somewhat slow. Oh well.
+
+ // Read key and value from data.
+ var nerr nonFatal
+ k := reflect.New(kt)
+ v := reflect.New(vt)
+ for len(b) > 0 {
+ x, n := decodeVarint(b)
+ if n == 0 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ wire := int(x) & 7
+ b = b[n:]
+
+ var err error
+ switch x >> 3 {
+ case 1:
+ b, err = unmarshalKey(b, valToPointer(k), wire)
+ case 2:
+ b, err = unmarshalVal(b, valToPointer(v), wire)
+ default:
+ err = errInternalBadWireType // skip unknown tag
+ }
+
+ if nerr.Merge(err) {
+ continue
+ }
+ if err != errInternalBadWireType {
+ return nil, err
+ }
+
+ // Skip past unknown fields.
+ b, err = skipField(b, wire)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Get map, allocate if needed.
+ m := f.asPointerTo(t).Elem() // an addressable map[K]T
+ if m.IsNil() {
+ m.Set(reflect.MakeMap(t))
+ }
+
+ // Insert into map.
+ m.SetMapIndex(k.Elem(), v.Elem())
+
+ return r, nerr.E
+ }
+}
+
+// makeUnmarshalOneof makes an unmarshaler for oneof fields.
+// for:
+// message Msg {
+// oneof F {
+// int64 X = 1;
+// float64 Y = 2;
+// }
+// }
+// typ is the type of the concrete entry for a oneof case (e.g. Msg_X).
+// ityp is the interface type of the oneof field (e.g. isMsg_F).
+// unmarshal is the unmarshaler for the base type of the oneof case (e.g. int64).
+// Note that this function will be called once for each case in the oneof.
+func makeUnmarshalOneof(typ, ityp reflect.Type, unmarshal unmarshaler) unmarshaler {
+ sf := typ.Field(0)
+ field0 := toField(&sf)
+ return func(b []byte, f pointer, w int) ([]byte, error) {
+ // Allocate holder for value.
+ v := reflect.New(typ)
+
+ // Unmarshal data into holder.
+ // We unmarshal into the first field of the holder object.
+ var err error
+ var nerr nonFatal
+ b, err = unmarshal(b, valToPointer(v).offset(field0), w)
+ if !nerr.Merge(err) {
+ return nil, err
+ }
+
+ // Write pointer to holder into target field.
+ f.asPointerTo(ityp).Elem().Set(v)
+
+ return b, nerr.E
+ }
+}
+
+// Error used by decode internally.
+var errInternalBadWireType = errors.New("proto: internal error: bad wiretype")
+
+// skipField skips past a field of type wire and returns the remaining bytes.
+func skipField(b []byte, wire int) ([]byte, error) {
+ switch wire {
+ case WireVarint:
+ _, k := decodeVarint(b)
+ if k == 0 {
+ return b, io.ErrUnexpectedEOF
+ }
+ b = b[k:]
+ case WireFixed32:
+ if len(b) < 4 {
+ return b, io.ErrUnexpectedEOF
+ }
+ b = b[4:]
+ case WireFixed64:
+ if len(b) < 8 {
+ return b, io.ErrUnexpectedEOF
+ }
+ b = b[8:]
+ case WireBytes:
+ m, k := decodeVarint(b)
+ if k == 0 || uint64(len(b)-k) < m {
+ return b, io.ErrUnexpectedEOF
+ }
+ b = b[uint64(k)+m:]
+ case WireStartGroup:
+ _, i := findEndGroup(b)
+ if i == -1 {
+ return b, io.ErrUnexpectedEOF
+ }
+ b = b[i:]
+ default:
+ return b, fmt.Errorf("proto: can't skip unknown wire type %d", wire)
+ }
+ return b, nil
+}
+
+// findEndGroup finds the index of the next EndGroup tag.
+// Groups may be nested, so the "next" EndGroup tag is the first
+// unpaired EndGroup.
+// findEndGroup returns the indexes of the start and end of the EndGroup tag.
+// Returns (-1,-1) if it can't find one.
+func findEndGroup(b []byte) (int, int) {
+ depth := 1
+ i := 0
+ for {
+ x, n := decodeVarint(b[i:])
+ if n == 0 {
+ return -1, -1
+ }
+ j := i
+ i += n
+ switch x & 7 {
+ case WireVarint:
+ _, k := decodeVarint(b[i:])
+ if k == 0 {
+ return -1, -1
+ }
+ i += k
+ case WireFixed32:
+ if len(b)-4 < i {
+ return -1, -1
+ }
+ i += 4
+ case WireFixed64:
+ if len(b)-8 < i {
+ return -1, -1
+ }
+ i += 8
+ case WireBytes:
+ m, k := decodeVarint(b[i:])
+ if k == 0 {
+ return -1, -1
+ }
+ i += k
+ if uint64(len(b)-i) < m {
+ return -1, -1
+ }
+ i += int(m)
+ case WireStartGroup:
+ depth++
+ case WireEndGroup:
+ depth--
+ if depth == 0 {
+ return j, i
+ }
+ default:
+ return -1, -1
+ }
+ }
+}
+
+// encodeVarint appends a varint-encoded integer to b and returns the result.
+func encodeVarint(b []byte, x uint64) []byte {
+ for x >= 1<<7 {
+ b = append(b, byte(x&0x7f|0x80))
+ x >>= 7
+ }
+ return append(b, byte(x))
+}
+
+// decodeVarint reads a varint-encoded integer from b.
+// Returns the decoded integer and the number of bytes read.
+// If there is an error, it returns 0,0.
+func decodeVarint(b []byte) (uint64, int) {
+ var x, y uint64
+ if len(b) == 0 {
+ goto bad
+ }
+ x = uint64(b[0])
+ if x < 0x80 {
+ return x, 1
+ }
+ x -= 0x80
+
+ if len(b) <= 1 {
+ goto bad
+ }
+ y = uint64(b[1])
+ x += y << 7
+ if y < 0x80 {
+ return x, 2
+ }
+ x -= 0x80 << 7
+
+ if len(b) <= 2 {
+ goto bad
+ }
+ y = uint64(b[2])
+ x += y << 14
+ if y < 0x80 {
+ return x, 3
+ }
+ x -= 0x80 << 14
+
+ if len(b) <= 3 {
+ goto bad
+ }
+ y = uint64(b[3])
+ x += y << 21
+ if y < 0x80 {
+ return x, 4
+ }
+ x -= 0x80 << 21
+
+ if len(b) <= 4 {
+ goto bad
+ }
+ y = uint64(b[4])
+ x += y << 28
+ if y < 0x80 {
+ return x, 5
+ }
+ x -= 0x80 << 28
+
+ if len(b) <= 5 {
+ goto bad
+ }
+ y = uint64(b[5])
+ x += y << 35
+ if y < 0x80 {
+ return x, 6
+ }
+ x -= 0x80 << 35
+
+ if len(b) <= 6 {
+ goto bad
+ }
+ y = uint64(b[6])
+ x += y << 42
+ if y < 0x80 {
+ return x, 7
+ }
+ x -= 0x80 << 42
+
+ if len(b) <= 7 {
+ goto bad
+ }
+ y = uint64(b[7])
+ x += y << 49
+ if y < 0x80 {
+ return x, 8
+ }
+ x -= 0x80 << 49
+
+ if len(b) <= 8 {
+ goto bad
+ }
+ y = uint64(b[8])
+ x += y << 56
+ if y < 0x80 {
+ return x, 9
+ }
+ x -= 0x80 << 56
+
+ if len(b) <= 9 {
+ goto bad
+ }
+ y = uint64(b[9])
+ x += y << 63
+ if y < 2 {
+ return x, 10
+ }
+
+bad:
+ return 0, 0
+}
diff --git a/vendor/github.com/golang/protobuf/proto/text.go b/vendor/github.com/golang/protobuf/proto/text.go
index 965876bf0..1aaee725b 100644
--- a/vendor/github.com/golang/protobuf/proto/text.go
+++ b/vendor/github.com/golang/protobuf/proto/text.go
@@ -50,7 +50,6 @@ import (
var (
newline = []byte("\n")
spaces = []byte(" ")
- gtNewline = []byte(">\n")
endBraceNewline = []byte("}\n")
backslashN = []byte{'\\', 'n'}
backslashR = []byte{'\\', 'r'}
@@ -170,11 +169,6 @@ func writeName(w *textWriter, props *Properties) error {
return nil
}
-// raw is the interface satisfied by RawMessage.
-type raw interface {
- Bytes() []byte
-}
-
func requiresQuotes(u string) bool {
// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
for _, ch := range u {
@@ -269,6 +263,10 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
props := sprops.Prop[i]
name := st.Field(i).Name
+ if name == "XXX_NoUnkeyedLiteral" {
+ continue
+ }
+
if strings.HasPrefix(name, "XXX_") {
// There are two XXX_ fields:
// XXX_unrecognized []byte
@@ -355,7 +353,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
return err
}
}
- if err := tm.writeAny(w, key, props.mkeyprop); err != nil {
+ if err := tm.writeAny(w, key, props.MapKeyProp); err != nil {
return err
}
if err := w.WriteByte('\n'); err != nil {
@@ -372,7 +370,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
return err
}
}
- if err := tm.writeAny(w, val, props.mvalprop); err != nil {
+ if err := tm.writeAny(w, val, props.MapValProp); err != nil {
return err
}
if err := w.WriteByte('\n'); err != nil {
@@ -436,12 +434,6 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
return err
}
}
- if b, ok := fv.Interface().(raw); ok {
- if err := writeRaw(w, b.Bytes()); err != nil {
- return err
- }
- continue
- }
// Enums have a String method, so writeAny will work fine.
if err := tm.writeAny(w, fv, props); err != nil {
@@ -455,7 +447,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
// Extensions (the XXX_extensions field).
pv := sv.Addr()
- if _, ok := extendable(pv.Interface()); ok {
+ if _, err := extendable(pv.Interface()); err == nil {
if err := tm.writeExtensions(w, pv); err != nil {
return err
}
@@ -464,27 +456,6 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
return nil
}
-// writeRaw writes an uninterpreted raw message.
-func writeRaw(w *textWriter, b []byte) error {
- if err := w.WriteByte('<'); err != nil {
- return err
- }
- if !w.compact {
- if err := w.WriteByte('\n'); err != nil {
- return err
- }
- }
- w.indent()
- if err := writeUnknownStruct(w, b); err != nil {
- return err
- }
- w.unindent()
- if err := w.WriteByte('>'); err != nil {
- return err
- }
- return nil
-}
-
// writeAny writes an arbitrary field.
func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error {
v = reflect.Indirect(v)
@@ -535,6 +506,19 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert
}
}
w.indent()
+ if v.CanAddr() {
+ // Calling v.Interface on a struct causes the reflect package to
+ // copy the entire struct. This is racy with the new Marshaler
+ // since we atomically update the XXX_sizecache.
+ //
+ // Thus, we retrieve a pointer to the struct if possible to avoid
+ // a race since v.Interface on the pointer doesn't copy the struct.
+ //
+ // If v is not addressable, then we are not worried about a race
+ // since it implies that the binary Marshaler cannot possibly be
+ // mutating this value.
+ v = v.Addr()
+ }
if etm, ok := v.Interface().(encoding.TextMarshaler); ok {
text, err := etm.MarshalText()
if err != nil {
@@ -543,8 +527,13 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert
if _, err = w.Write(text); err != nil {
return err
}
- } else if err := tm.writeStruct(w, v); err != nil {
- return err
+ } else {
+ if v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+ if err := tm.writeStruct(w, v); err != nil {
+ return err
+ }
}
w.unindent()
if err := w.WriteByte(ket); err != nil {
diff --git a/vendor/github.com/golang/protobuf/proto/text_parser.go b/vendor/github.com/golang/protobuf/proto/text_parser.go
index 5e14513f2..bb55a3af2 100644
--- a/vendor/github.com/golang/protobuf/proto/text_parser.go
+++ b/vendor/github.com/golang/protobuf/proto/text_parser.go
@@ -206,7 +206,6 @@ func (p *textParser) advance() {
var (
errBadUTF8 = errors.New("proto: bad UTF-8")
- errBadHex = errors.New("proto: bad hexadecimal")
)
func unquoteC(s string, quote rune) (string, error) {
@@ -277,60 +276,47 @@ func unescape(s string) (ch string, tail string, err error) {
return "?", s, nil // trigraph workaround
case '\'', '"', '\\':
return string(r), s, nil
- case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X':
+ case '0', '1', '2', '3', '4', '5', '6', '7':
if len(s) < 2 {
return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
}
- base := 8
- ss := s[:2]
+ ss := string(r) + s[:2]
s = s[2:]
- if r == 'x' || r == 'X' {
- base = 16
- } else {
- ss = string(r) + ss
- }
- i, err := strconv.ParseUint(ss, base, 8)
+ i, err := strconv.ParseUint(ss, 8, 8)
if err != nil {
- return "", "", err
+ return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss)
}
return string([]byte{byte(i)}), s, nil
- case 'u', 'U':
- n := 4
- if r == 'U' {
+ case 'x', 'X', 'u', 'U':
+ var n int
+ switch r {
+ case 'x', 'X':
+ n = 2
+ case 'u':
+ n = 4
+ case 'U':
n = 8
}
if len(s) < n {
- return "", "", fmt.Errorf(`\%c requires %d digits`, r, n)
- }
-
- bs := make([]byte, n/2)
- for i := 0; i < n; i += 2 {
- a, ok1 := unhex(s[i])
- b, ok2 := unhex(s[i+1])
- if !ok1 || !ok2 {
- return "", "", errBadHex
- }
- bs[i/2] = a<<4 | b
+ return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n)
}
+ ss := s[:n]
s = s[n:]
- return string(bs), s, nil
+ i, err := strconv.ParseUint(ss, 16, 64)
+ if err != nil {
+ return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss)
+ }
+ if r == 'x' || r == 'X' {
+ return string([]byte{byte(i)}), s, nil
+ }
+ if i > utf8.MaxRune {
+ return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss)
+ }
+ return string(i), s, nil
}
return "", "", fmt.Errorf(`unknown escape \%c`, r)
}
-// Adapted from src/pkg/strconv/quote.go.
-func unhex(b byte) (v byte, ok bool) {
- switch {
- case '0' <= b && b <= '9':
- return b - '0', true
- case 'a' <= b && b <= 'f':
- return b - 'a' + 10, true
- case 'A' <= b && b <= 'F':
- return b - 'A' + 10, true
- }
- return 0, false
-}
-
// Back off the parser by one token. Can only be done between calls to next().
// It makes the next advance() a no-op.
func (p *textParser) back() { p.backed = true }
@@ -644,17 +630,17 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
if err := p.consumeToken(":"); err != nil {
return err
}
- if err := p.readAny(key, props.mkeyprop); err != nil {
+ if err := p.readAny(key, props.MapKeyProp); err != nil {
return err
}
if err := p.consumeOptionalSeparator(); err != nil {
return err
}
case "value":
- if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil {
+ if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil {
return err
}
- if err := p.readAny(val, props.mvalprop); err != nil {
+ if err := p.readAny(val, props.MapValProp); err != nil {
return err
}
if err := p.consumeOptionalSeparator(); err != nil {
@@ -728,6 +714,9 @@ func (p *textParser) consumeExtName() (string, error) {
if tok.err != nil {
return "", p.errorf("unrecognized type_url or extension name: %s", tok.err)
}
+ if p.done && tok.value != "]" {
+ return "", p.errorf("unclosed type_url or extension name")
+ }
}
return strings.Join(parts, ""), nil
}
@@ -865,7 +854,7 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error {
return p.readStruct(fv, terminator)
case reflect.Uint32:
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
- fv.SetUint(x)
+ fv.SetUint(uint64(x))
return nil
}
case reflect.Uint64:
@@ -883,13 +872,9 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error {
// UnmarshalText returns *RequiredNotSetError.
func UnmarshalText(s string, pb Message) error {
if um, ok := pb.(encoding.TextUnmarshaler); ok {
- err := um.UnmarshalText([]byte(s))
- return err
+ return um.UnmarshalText([]byte(s))
}
pb.Reset()
v := reflect.ValueOf(pb)
- if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil {
- return pe
- }
- return nil
+ return newTextParser(s).readStruct(v.Elem(), "")
}
diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile
deleted file mode 100644
index 41a2d04d0..000000000
--- a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile
+++ /dev/null
@@ -1,36 +0,0 @@
-# Go support for Protocol Buffers - Google's data interchange format
-#
-# Copyright 2010 The Go Authors. All rights reserved.
-# https://github.com/golang/protobuf
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# Not stored here, but descriptor.proto is in https://github.com/google/protobuf/
-# at src/google/protobuf/descriptor.proto
-regenerate:
- @echo WARNING! THIS RULE IS PROBABLY NOT RIGHT FOR YOUR INSTALLATION
- protoc --go_out=../../../../.. -I$(HOME)/src/protobuf/include $(HOME)/src/protobuf/include/google/protobuf/descriptor.proto
diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go
index 63cf2c80a..1ded05bbe 100644
--- a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go
+++ b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go
@@ -1,39 +1,13 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/descriptor.proto
-/*
-Package descriptor is a generated protocol buffer package.
-
-It is generated from these files:
- google/protobuf/descriptor.proto
-
-It has these top-level messages:
- FileDescriptorSet
- FileDescriptorProto
- DescriptorProto
- FieldDescriptorProto
- OneofDescriptorProto
- EnumDescriptorProto
- EnumValueDescriptorProto
- ServiceDescriptorProto
- MethodDescriptorProto
- FileOptions
- MessageOptions
- FieldOptions
- OneofOptions
- EnumOptions
- EnumValueOptions
- ServiceOptions
- MethodOptions
- UninterpretedOption
- SourceCodeInfo
- GeneratedCodeInfo
-*/
package descriptor
-import proto "github.com/golang/protobuf/proto"
-import fmt "fmt"
-import math "math"
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ math "math"
+)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@@ -44,7 +18,7 @@ var _ = math.Inf
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type FieldDescriptorProto_Type int32
@@ -100,6 +74,7 @@ var FieldDescriptorProto_Type_name = map[int32]string{
17: "TYPE_SINT32",
18: "TYPE_SINT64",
}
+
var FieldDescriptorProto_Type_value = map[string]int32{
"TYPE_DOUBLE": 1,
"TYPE_FLOAT": 2,
@@ -126,9 +101,11 @@ func (x FieldDescriptorProto_Type) Enum() *FieldDescriptorProto_Type {
*p = x
return p
}
+
func (x FieldDescriptorProto_Type) String() string {
return proto.EnumName(FieldDescriptorProto_Type_name, int32(x))
}
+
func (x *FieldDescriptorProto_Type) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(FieldDescriptorProto_Type_value, data, "FieldDescriptorProto_Type")
if err != nil {
@@ -137,7 +114,10 @@ func (x *FieldDescriptorProto_Type) UnmarshalJSON(data []byte) error {
*x = FieldDescriptorProto_Type(value)
return nil
}
-func (FieldDescriptorProto_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3, 0} }
+
+func (FieldDescriptorProto_Type) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{4, 0}
+}
type FieldDescriptorProto_Label int32
@@ -153,6 +133,7 @@ var FieldDescriptorProto_Label_name = map[int32]string{
2: "LABEL_REQUIRED",
3: "LABEL_REPEATED",
}
+
var FieldDescriptorProto_Label_value = map[string]int32{
"LABEL_OPTIONAL": 1,
"LABEL_REQUIRED": 2,
@@ -164,9 +145,11 @@ func (x FieldDescriptorProto_Label) Enum() *FieldDescriptorProto_Label {
*p = x
return p
}
+
func (x FieldDescriptorProto_Label) String() string {
return proto.EnumName(FieldDescriptorProto_Label_name, int32(x))
}
+
func (x *FieldDescriptorProto_Label) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(FieldDescriptorProto_Label_value, data, "FieldDescriptorProto_Label")
if err != nil {
@@ -175,8 +158,9 @@ func (x *FieldDescriptorProto_Label) UnmarshalJSON(data []byte) error {
*x = FieldDescriptorProto_Label(value)
return nil
}
+
func (FieldDescriptorProto_Label) EnumDescriptor() ([]byte, []int) {
- return fileDescriptor0, []int{3, 1}
+ return fileDescriptor_e5baabe45344a177, []int{4, 1}
}
// Generated classes can be optimized for speed or code size.
@@ -194,6 +178,7 @@ var FileOptions_OptimizeMode_name = map[int32]string{
2: "CODE_SIZE",
3: "LITE_RUNTIME",
}
+
var FileOptions_OptimizeMode_value = map[string]int32{
"SPEED": 1,
"CODE_SIZE": 2,
@@ -205,9 +190,11 @@ func (x FileOptions_OptimizeMode) Enum() *FileOptions_OptimizeMode {
*p = x
return p
}
+
func (x FileOptions_OptimizeMode) String() string {
return proto.EnumName(FileOptions_OptimizeMode_name, int32(x))
}
+
func (x *FileOptions_OptimizeMode) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(FileOptions_OptimizeMode_value, data, "FileOptions_OptimizeMode")
if err != nil {
@@ -216,7 +203,10 @@ func (x *FileOptions_OptimizeMode) UnmarshalJSON(data []byte) error {
*x = FileOptions_OptimizeMode(value)
return nil
}
-func (FileOptions_OptimizeMode) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{9, 0} }
+
+func (FileOptions_OptimizeMode) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{10, 0}
+}
type FieldOptions_CType int32
@@ -232,6 +222,7 @@ var FieldOptions_CType_name = map[int32]string{
1: "CORD",
2: "STRING_PIECE",
}
+
var FieldOptions_CType_value = map[string]int32{
"STRING": 0,
"CORD": 1,
@@ -243,9 +234,11 @@ func (x FieldOptions_CType) Enum() *FieldOptions_CType {
*p = x
return p
}
+
func (x FieldOptions_CType) String() string {
return proto.EnumName(FieldOptions_CType_name, int32(x))
}
+
func (x *FieldOptions_CType) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(FieldOptions_CType_value, data, "FieldOptions_CType")
if err != nil {
@@ -254,7 +247,10 @@ func (x *FieldOptions_CType) UnmarshalJSON(data []byte) error {
*x = FieldOptions_CType(value)
return nil
}
-func (FieldOptions_CType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{11, 0} }
+
+func (FieldOptions_CType) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{12, 0}
+}
type FieldOptions_JSType int32
@@ -272,6 +268,7 @@ var FieldOptions_JSType_name = map[int32]string{
1: "JS_STRING",
2: "JS_NUMBER",
}
+
var FieldOptions_JSType_value = map[string]int32{
"JS_NORMAL": 0,
"JS_STRING": 1,
@@ -283,9 +280,11 @@ func (x FieldOptions_JSType) Enum() *FieldOptions_JSType {
*p = x
return p
}
+
func (x FieldOptions_JSType) String() string {
return proto.EnumName(FieldOptions_JSType_name, int32(x))
}
+
func (x *FieldOptions_JSType) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(FieldOptions_JSType_value, data, "FieldOptions_JSType")
if err != nil {
@@ -294,7 +293,10 @@ func (x *FieldOptions_JSType) UnmarshalJSON(data []byte) error {
*x = FieldOptions_JSType(value)
return nil
}
-func (FieldOptions_JSType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{11, 1} }
+
+func (FieldOptions_JSType) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{12, 1}
+}
// Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
// or neither? HTTP based RPC implementation may choose GET verb for safe
@@ -312,6 +314,7 @@ var MethodOptions_IdempotencyLevel_name = map[int32]string{
1: "NO_SIDE_EFFECTS",
2: "IDEMPOTENT",
}
+
var MethodOptions_IdempotencyLevel_value = map[string]int32{
"IDEMPOTENCY_UNKNOWN": 0,
"NO_SIDE_EFFECTS": 1,
@@ -323,9 +326,11 @@ func (x MethodOptions_IdempotencyLevel) Enum() *MethodOptions_IdempotencyLevel {
*p = x
return p
}
+
func (x MethodOptions_IdempotencyLevel) String() string {
return proto.EnumName(MethodOptions_IdempotencyLevel_name, int32(x))
}
+
func (x *MethodOptions_IdempotencyLevel) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(MethodOptions_IdempotencyLevel_value, data, "MethodOptions_IdempotencyLevel")
if err != nil {
@@ -334,21 +339,44 @@ func (x *MethodOptions_IdempotencyLevel) UnmarshalJSON(data []byte) error {
*x = MethodOptions_IdempotencyLevel(value)
return nil
}
+
func (MethodOptions_IdempotencyLevel) EnumDescriptor() ([]byte, []int) {
- return fileDescriptor0, []int{16, 0}
+ return fileDescriptor_e5baabe45344a177, []int{17, 0}
}
// The protocol compiler can output a FileDescriptorSet containing the .proto
// files it parses.
type FileDescriptorSet struct {
- File []*FileDescriptorProto `protobuf:"bytes,1,rep,name=file" json:"file,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ File []*FileDescriptorProto `protobuf:"bytes,1,rep,name=file" json:"file,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *FileDescriptorSet) Reset() { *m = FileDescriptorSet{} }
+func (m *FileDescriptorSet) String() string { return proto.CompactTextString(m) }
+func (*FileDescriptorSet) ProtoMessage() {}
+func (*FileDescriptorSet) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{0}
+}
+
+func (m *FileDescriptorSet) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_FileDescriptorSet.Unmarshal(m, b)
+}
+func (m *FileDescriptorSet) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_FileDescriptorSet.Marshal(b, m, deterministic)
+}
+func (m *FileDescriptorSet) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_FileDescriptorSet.Merge(m, src)
+}
+func (m *FileDescriptorSet) XXX_Size() int {
+ return xxx_messageInfo_FileDescriptorSet.Size(m)
+}
+func (m *FileDescriptorSet) XXX_DiscardUnknown() {
+ xxx_messageInfo_FileDescriptorSet.DiscardUnknown(m)
}
-func (m *FileDescriptorSet) Reset() { *m = FileDescriptorSet{} }
-func (m *FileDescriptorSet) String() string { return proto.CompactTextString(m) }
-func (*FileDescriptorSet) ProtoMessage() {}
-func (*FileDescriptorSet) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
+var xxx_messageInfo_FileDescriptorSet proto.InternalMessageInfo
func (m *FileDescriptorSet) GetFile() []*FileDescriptorProto {
if m != nil {
@@ -381,14 +409,36 @@ type FileDescriptorProto struct {
SourceCodeInfo *SourceCodeInfo `protobuf:"bytes,9,opt,name=source_code_info,json=sourceCodeInfo" json:"source_code_info,omitempty"`
// The syntax of the proto file.
// The supported values are "proto2" and "proto3".
- Syntax *string `protobuf:"bytes,12,opt,name=syntax" json:"syntax,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ Syntax *string `protobuf:"bytes,12,opt,name=syntax" json:"syntax,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *FileDescriptorProto) Reset() { *m = FileDescriptorProto{} }
+func (m *FileDescriptorProto) String() string { return proto.CompactTextString(m) }
+func (*FileDescriptorProto) ProtoMessage() {}
+func (*FileDescriptorProto) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{1}
+}
+
+func (m *FileDescriptorProto) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_FileDescriptorProto.Unmarshal(m, b)
+}
+func (m *FileDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_FileDescriptorProto.Marshal(b, m, deterministic)
+}
+func (m *FileDescriptorProto) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_FileDescriptorProto.Merge(m, src)
+}
+func (m *FileDescriptorProto) XXX_Size() int {
+ return xxx_messageInfo_FileDescriptorProto.Size(m)
+}
+func (m *FileDescriptorProto) XXX_DiscardUnknown() {
+ xxx_messageInfo_FileDescriptorProto.DiscardUnknown(m)
}
-func (m *FileDescriptorProto) Reset() { *m = FileDescriptorProto{} }
-func (m *FileDescriptorProto) String() string { return proto.CompactTextString(m) }
-func (*FileDescriptorProto) ProtoMessage() {}
-func (*FileDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
+var xxx_messageInfo_FileDescriptorProto proto.InternalMessageInfo
func (m *FileDescriptorProto) GetName() string {
if m != nil && m.Name != nil {
@@ -487,14 +537,36 @@ type DescriptorProto struct {
ReservedRange []*DescriptorProto_ReservedRange `protobuf:"bytes,9,rep,name=reserved_range,json=reservedRange" json:"reserved_range,omitempty"`
// Reserved field names, which may not be used by fields in the same message.
// A given name may only be reserved once.
- ReservedName []string `protobuf:"bytes,10,rep,name=reserved_name,json=reservedName" json:"reserved_name,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ ReservedName []string `protobuf:"bytes,10,rep,name=reserved_name,json=reservedName" json:"reserved_name,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *DescriptorProto) Reset() { *m = DescriptorProto{} }
+func (m *DescriptorProto) String() string { return proto.CompactTextString(m) }
+func (*DescriptorProto) ProtoMessage() {}
+func (*DescriptorProto) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{2}
+}
+
+func (m *DescriptorProto) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_DescriptorProto.Unmarshal(m, b)
+}
+func (m *DescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_DescriptorProto.Marshal(b, m, deterministic)
+}
+func (m *DescriptorProto) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_DescriptorProto.Merge(m, src)
+}
+func (m *DescriptorProto) XXX_Size() int {
+ return xxx_messageInfo_DescriptorProto.Size(m)
+}
+func (m *DescriptorProto) XXX_DiscardUnknown() {
+ xxx_messageInfo_DescriptorProto.DiscardUnknown(m)
}
-func (m *DescriptorProto) Reset() { *m = DescriptorProto{} }
-func (m *DescriptorProto) String() string { return proto.CompactTextString(m) }
-func (*DescriptorProto) ProtoMessage() {}
-func (*DescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
+var xxx_messageInfo_DescriptorProto proto.InternalMessageInfo
func (m *DescriptorProto) GetName() string {
if m != nil && m.Name != nil {
@@ -567,17 +639,38 @@ func (m *DescriptorProto) GetReservedName() []string {
}
type DescriptorProto_ExtensionRange struct {
- Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"`
- End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"`
+ End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"`
+ Options *ExtensionRangeOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
func (m *DescriptorProto_ExtensionRange) Reset() { *m = DescriptorProto_ExtensionRange{} }
func (m *DescriptorProto_ExtensionRange) String() string { return proto.CompactTextString(m) }
func (*DescriptorProto_ExtensionRange) ProtoMessage() {}
func (*DescriptorProto_ExtensionRange) Descriptor() ([]byte, []int) {
- return fileDescriptor0, []int{2, 0}
+ return fileDescriptor_e5baabe45344a177, []int{2, 0}
+}
+
+func (m *DescriptorProto_ExtensionRange) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_DescriptorProto_ExtensionRange.Unmarshal(m, b)
}
+func (m *DescriptorProto_ExtensionRange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_DescriptorProto_ExtensionRange.Marshal(b, m, deterministic)
+}
+func (m *DescriptorProto_ExtensionRange) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_DescriptorProto_ExtensionRange.Merge(m, src)
+}
+func (m *DescriptorProto_ExtensionRange) XXX_Size() int {
+ return xxx_messageInfo_DescriptorProto_ExtensionRange.Size(m)
+}
+func (m *DescriptorProto_ExtensionRange) XXX_DiscardUnknown() {
+ xxx_messageInfo_DescriptorProto_ExtensionRange.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_DescriptorProto_ExtensionRange proto.InternalMessageInfo
func (m *DescriptorProto_ExtensionRange) GetStart() int32 {
if m != nil && m.Start != nil {
@@ -593,21 +686,48 @@ func (m *DescriptorProto_ExtensionRange) GetEnd() int32 {
return 0
}
+func (m *DescriptorProto_ExtensionRange) GetOptions() *ExtensionRangeOptions {
+ if m != nil {
+ return m.Options
+ }
+ return nil
+}
+
// Range of reserved tag numbers. Reserved tag numbers may not be used by
// fields or extension ranges in the same message. Reserved ranges may
// not overlap.
type DescriptorProto_ReservedRange struct {
- Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"`
- End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"`
+ End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
func (m *DescriptorProto_ReservedRange) Reset() { *m = DescriptorProto_ReservedRange{} }
func (m *DescriptorProto_ReservedRange) String() string { return proto.CompactTextString(m) }
func (*DescriptorProto_ReservedRange) ProtoMessage() {}
func (*DescriptorProto_ReservedRange) Descriptor() ([]byte, []int) {
- return fileDescriptor0, []int{2, 1}
+ return fileDescriptor_e5baabe45344a177, []int{2, 1}
+}
+
+func (m *DescriptorProto_ReservedRange) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_DescriptorProto_ReservedRange.Unmarshal(m, b)
+}
+func (m *DescriptorProto_ReservedRange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_DescriptorProto_ReservedRange.Marshal(b, m, deterministic)
+}
+func (m *DescriptorProto_ReservedRange) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_DescriptorProto_ReservedRange.Merge(m, src)
}
+func (m *DescriptorProto_ReservedRange) XXX_Size() int {
+ return xxx_messageInfo_DescriptorProto_ReservedRange.Size(m)
+}
+func (m *DescriptorProto_ReservedRange) XXX_DiscardUnknown() {
+ xxx_messageInfo_DescriptorProto_ReservedRange.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_DescriptorProto_ReservedRange proto.InternalMessageInfo
func (m *DescriptorProto_ReservedRange) GetStart() int32 {
if m != nil && m.Start != nil {
@@ -623,6 +743,55 @@ func (m *DescriptorProto_ReservedRange) GetEnd() int32 {
return 0
}
+type ExtensionRangeOptions struct {
+ // The parser stores options it doesn't recognize here. See above.
+ UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ proto.XXX_InternalExtensions `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *ExtensionRangeOptions) Reset() { *m = ExtensionRangeOptions{} }
+func (m *ExtensionRangeOptions) String() string { return proto.CompactTextString(m) }
+func (*ExtensionRangeOptions) ProtoMessage() {}
+func (*ExtensionRangeOptions) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{3}
+}
+
+var extRange_ExtensionRangeOptions = []proto.ExtensionRange{
+ {Start: 1000, End: 536870911},
+}
+
+func (*ExtensionRangeOptions) ExtensionRangeArray() []proto.ExtensionRange {
+ return extRange_ExtensionRangeOptions
+}
+
+func (m *ExtensionRangeOptions) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_ExtensionRangeOptions.Unmarshal(m, b)
+}
+func (m *ExtensionRangeOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_ExtensionRangeOptions.Marshal(b, m, deterministic)
+}
+func (m *ExtensionRangeOptions) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ExtensionRangeOptions.Merge(m, src)
+}
+func (m *ExtensionRangeOptions) XXX_Size() int {
+ return xxx_messageInfo_ExtensionRangeOptions.Size(m)
+}
+func (m *ExtensionRangeOptions) XXX_DiscardUnknown() {
+ xxx_messageInfo_ExtensionRangeOptions.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ExtensionRangeOptions proto.InternalMessageInfo
+
+func (m *ExtensionRangeOptions) GetUninterpretedOption() []*UninterpretedOption {
+ if m != nil {
+ return m.UninterpretedOption
+ }
+ return nil
+}
+
// Describes a field within a message.
type FieldDescriptorProto struct {
Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
@@ -653,15 +822,37 @@ type FieldDescriptorProto struct {
// user has set a "json_name" option on this field, that option's value
// will be used. Otherwise, it's deduced from the field's name by converting
// it to camelCase.
- JsonName *string `protobuf:"bytes,10,opt,name=json_name,json=jsonName" json:"json_name,omitempty"`
- Options *FieldOptions `protobuf:"bytes,8,opt,name=options" json:"options,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ JsonName *string `protobuf:"bytes,10,opt,name=json_name,json=jsonName" json:"json_name,omitempty"`
+ Options *FieldOptions `protobuf:"bytes,8,opt,name=options" json:"options,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *FieldDescriptorProto) Reset() { *m = FieldDescriptorProto{} }
+func (m *FieldDescriptorProto) String() string { return proto.CompactTextString(m) }
+func (*FieldDescriptorProto) ProtoMessage() {}
+func (*FieldDescriptorProto) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{4}
}
-func (m *FieldDescriptorProto) Reset() { *m = FieldDescriptorProto{} }
-func (m *FieldDescriptorProto) String() string { return proto.CompactTextString(m) }
-func (*FieldDescriptorProto) ProtoMessage() {}
-func (*FieldDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
+func (m *FieldDescriptorProto) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_FieldDescriptorProto.Unmarshal(m, b)
+}
+func (m *FieldDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_FieldDescriptorProto.Marshal(b, m, deterministic)
+}
+func (m *FieldDescriptorProto) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_FieldDescriptorProto.Merge(m, src)
+}
+func (m *FieldDescriptorProto) XXX_Size() int {
+ return xxx_messageInfo_FieldDescriptorProto.Size(m)
+}
+func (m *FieldDescriptorProto) XXX_DiscardUnknown() {
+ xxx_messageInfo_FieldDescriptorProto.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_FieldDescriptorProto proto.InternalMessageInfo
func (m *FieldDescriptorProto) GetName() string {
if m != nil && m.Name != nil {
@@ -735,15 +926,37 @@ func (m *FieldDescriptorProto) GetOptions() *FieldOptions {
// Describes a oneof.
type OneofDescriptorProto struct {
- Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
- Options *OneofOptions `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ Options *OneofOptions `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *OneofDescriptorProto) Reset() { *m = OneofDescriptorProto{} }
+func (m *OneofDescriptorProto) String() string { return proto.CompactTextString(m) }
+func (*OneofDescriptorProto) ProtoMessage() {}
+func (*OneofDescriptorProto) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{5}
+}
+
+func (m *OneofDescriptorProto) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_OneofDescriptorProto.Unmarshal(m, b)
+}
+func (m *OneofDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_OneofDescriptorProto.Marshal(b, m, deterministic)
+}
+func (m *OneofDescriptorProto) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_OneofDescriptorProto.Merge(m, src)
+}
+func (m *OneofDescriptorProto) XXX_Size() int {
+ return xxx_messageInfo_OneofDescriptorProto.Size(m)
+}
+func (m *OneofDescriptorProto) XXX_DiscardUnknown() {
+ xxx_messageInfo_OneofDescriptorProto.DiscardUnknown(m)
}
-func (m *OneofDescriptorProto) Reset() { *m = OneofDescriptorProto{} }
-func (m *OneofDescriptorProto) String() string { return proto.CompactTextString(m) }
-func (*OneofDescriptorProto) ProtoMessage() {}
-func (*OneofDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
+var xxx_messageInfo_OneofDescriptorProto proto.InternalMessageInfo
func (m *OneofDescriptorProto) GetName() string {
if m != nil && m.Name != nil {
@@ -761,16 +974,45 @@ func (m *OneofDescriptorProto) GetOptions() *OneofOptions {
// Describes an enum type.
type EnumDescriptorProto struct {
- Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
- Value []*EnumValueDescriptorProto `protobuf:"bytes,2,rep,name=value" json:"value,omitempty"`
- Options *EnumOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ Value []*EnumValueDescriptorProto `protobuf:"bytes,2,rep,name=value" json:"value,omitempty"`
+ Options *EnumOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"`
+ // Range of reserved numeric values. Reserved numeric values may not be used
+ // by enum values in the same enum declaration. Reserved ranges may not
+ // overlap.
+ ReservedRange []*EnumDescriptorProto_EnumReservedRange `protobuf:"bytes,4,rep,name=reserved_range,json=reservedRange" json:"reserved_range,omitempty"`
+ // Reserved enum value names, which may not be reused. A given name may only
+ // be reserved once.
+ ReservedName []string `protobuf:"bytes,5,rep,name=reserved_name,json=reservedName" json:"reserved_name,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *EnumDescriptorProto) Reset() { *m = EnumDescriptorProto{} }
+func (m *EnumDescriptorProto) String() string { return proto.CompactTextString(m) }
+func (*EnumDescriptorProto) ProtoMessage() {}
+func (*EnumDescriptorProto) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{6}
+}
+
+func (m *EnumDescriptorProto) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_EnumDescriptorProto.Unmarshal(m, b)
+}
+func (m *EnumDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_EnumDescriptorProto.Marshal(b, m, deterministic)
+}
+func (m *EnumDescriptorProto) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_EnumDescriptorProto.Merge(m, src)
+}
+func (m *EnumDescriptorProto) XXX_Size() int {
+ return xxx_messageInfo_EnumDescriptorProto.Size(m)
+}
+func (m *EnumDescriptorProto) XXX_DiscardUnknown() {
+ xxx_messageInfo_EnumDescriptorProto.DiscardUnknown(m)
}
-func (m *EnumDescriptorProto) Reset() { *m = EnumDescriptorProto{} }
-func (m *EnumDescriptorProto) String() string { return proto.CompactTextString(m) }
-func (*EnumDescriptorProto) ProtoMessage() {}
-func (*EnumDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
+var xxx_messageInfo_EnumDescriptorProto proto.InternalMessageInfo
func (m *EnumDescriptorProto) GetName() string {
if m != nil && m.Name != nil {
@@ -793,18 +1035,107 @@ func (m *EnumDescriptorProto) GetOptions() *EnumOptions {
return nil
}
+func (m *EnumDescriptorProto) GetReservedRange() []*EnumDescriptorProto_EnumReservedRange {
+ if m != nil {
+ return m.ReservedRange
+ }
+ return nil
+}
+
+func (m *EnumDescriptorProto) GetReservedName() []string {
+ if m != nil {
+ return m.ReservedName
+ }
+ return nil
+}
+
+// Range of reserved numeric values. Reserved values may not be used by
+// entries in the same enum. Reserved ranges may not overlap.
+//
+// Note that this is distinct from DescriptorProto.ReservedRange in that it
+// is inclusive such that it can appropriately represent the entire int32
+// domain.
+type EnumDescriptorProto_EnumReservedRange struct {
+ Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"`
+ End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *EnumDescriptorProto_EnumReservedRange) Reset() { *m = EnumDescriptorProto_EnumReservedRange{} }
+func (m *EnumDescriptorProto_EnumReservedRange) String() string { return proto.CompactTextString(m) }
+func (*EnumDescriptorProto_EnumReservedRange) ProtoMessage() {}
+func (*EnumDescriptorProto_EnumReservedRange) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{6, 0}
+}
+
+func (m *EnumDescriptorProto_EnumReservedRange) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Unmarshal(m, b)
+}
+func (m *EnumDescriptorProto_EnumReservedRange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Marshal(b, m, deterministic)
+}
+func (m *EnumDescriptorProto_EnumReservedRange) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Merge(m, src)
+}
+func (m *EnumDescriptorProto_EnumReservedRange) XXX_Size() int {
+ return xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.Size(m)
+}
+func (m *EnumDescriptorProto_EnumReservedRange) XXX_DiscardUnknown() {
+ xxx_messageInfo_EnumDescriptorProto_EnumReservedRange.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_EnumDescriptorProto_EnumReservedRange proto.InternalMessageInfo
+
+func (m *EnumDescriptorProto_EnumReservedRange) GetStart() int32 {
+ if m != nil && m.Start != nil {
+ return *m.Start
+ }
+ return 0
+}
+
+func (m *EnumDescriptorProto_EnumReservedRange) GetEnd() int32 {
+ if m != nil && m.End != nil {
+ return *m.End
+ }
+ return 0
+}
+
// Describes a value within an enum.
type EnumValueDescriptorProto struct {
- Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
- Number *int32 `protobuf:"varint,2,opt,name=number" json:"number,omitempty"`
- Options *EnumValueOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ Number *int32 `protobuf:"varint,2,opt,name=number" json:"number,omitempty"`
+ Options *EnumValueOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *EnumValueDescriptorProto) Reset() { *m = EnumValueDescriptorProto{} }
+func (m *EnumValueDescriptorProto) String() string { return proto.CompactTextString(m) }
+func (*EnumValueDescriptorProto) ProtoMessage() {}
+func (*EnumValueDescriptorProto) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{7}
+}
+
+func (m *EnumValueDescriptorProto) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_EnumValueDescriptorProto.Unmarshal(m, b)
+}
+func (m *EnumValueDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_EnumValueDescriptorProto.Marshal(b, m, deterministic)
+}
+func (m *EnumValueDescriptorProto) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_EnumValueDescriptorProto.Merge(m, src)
+}
+func (m *EnumValueDescriptorProto) XXX_Size() int {
+ return xxx_messageInfo_EnumValueDescriptorProto.Size(m)
+}
+func (m *EnumValueDescriptorProto) XXX_DiscardUnknown() {
+ xxx_messageInfo_EnumValueDescriptorProto.DiscardUnknown(m)
}
-func (m *EnumValueDescriptorProto) Reset() { *m = EnumValueDescriptorProto{} }
-func (m *EnumValueDescriptorProto) String() string { return proto.CompactTextString(m) }
-func (*EnumValueDescriptorProto) ProtoMessage() {}
-func (*EnumValueDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
+var xxx_messageInfo_EnumValueDescriptorProto proto.InternalMessageInfo
func (m *EnumValueDescriptorProto) GetName() string {
if m != nil && m.Name != nil {
@@ -829,16 +1160,38 @@ func (m *EnumValueDescriptorProto) GetOptions() *EnumValueOptions {
// Describes a service.
type ServiceDescriptorProto struct {
- Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
- Method []*MethodDescriptorProto `protobuf:"bytes,2,rep,name=method" json:"method,omitempty"`
- Options *ServiceOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ Method []*MethodDescriptorProto `protobuf:"bytes,2,rep,name=method" json:"method,omitempty"`
+ Options *ServiceOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *ServiceDescriptorProto) Reset() { *m = ServiceDescriptorProto{} }
+func (m *ServiceDescriptorProto) String() string { return proto.CompactTextString(m) }
+func (*ServiceDescriptorProto) ProtoMessage() {}
+func (*ServiceDescriptorProto) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{8}
+}
+
+func (m *ServiceDescriptorProto) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_ServiceDescriptorProto.Unmarshal(m, b)
+}
+func (m *ServiceDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_ServiceDescriptorProto.Marshal(b, m, deterministic)
+}
+func (m *ServiceDescriptorProto) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ServiceDescriptorProto.Merge(m, src)
+}
+func (m *ServiceDescriptorProto) XXX_Size() int {
+ return xxx_messageInfo_ServiceDescriptorProto.Size(m)
+}
+func (m *ServiceDescriptorProto) XXX_DiscardUnknown() {
+ xxx_messageInfo_ServiceDescriptorProto.DiscardUnknown(m)
}
-func (m *ServiceDescriptorProto) Reset() { *m = ServiceDescriptorProto{} }
-func (m *ServiceDescriptorProto) String() string { return proto.CompactTextString(m) }
-func (*ServiceDescriptorProto) ProtoMessage() {}
-func (*ServiceDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
+var xxx_messageInfo_ServiceDescriptorProto proto.InternalMessageInfo
func (m *ServiceDescriptorProto) GetName() string {
if m != nil && m.Name != nil {
@@ -872,14 +1225,36 @@ type MethodDescriptorProto struct {
// Identifies if client streams multiple client messages
ClientStreaming *bool `protobuf:"varint,5,opt,name=client_streaming,json=clientStreaming,def=0" json:"client_streaming,omitempty"`
// Identifies if server streams multiple server messages
- ServerStreaming *bool `protobuf:"varint,6,opt,name=server_streaming,json=serverStreaming,def=0" json:"server_streaming,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ ServerStreaming *bool `protobuf:"varint,6,opt,name=server_streaming,json=serverStreaming,def=0" json:"server_streaming,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *MethodDescriptorProto) Reset() { *m = MethodDescriptorProto{} }
+func (m *MethodDescriptorProto) String() string { return proto.CompactTextString(m) }
+func (*MethodDescriptorProto) ProtoMessage() {}
+func (*MethodDescriptorProto) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{9}
+}
+
+func (m *MethodDescriptorProto) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_MethodDescriptorProto.Unmarshal(m, b)
+}
+func (m *MethodDescriptorProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_MethodDescriptorProto.Marshal(b, m, deterministic)
+}
+func (m *MethodDescriptorProto) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MethodDescriptorProto.Merge(m, src)
+}
+func (m *MethodDescriptorProto) XXX_Size() int {
+ return xxx_messageInfo_MethodDescriptorProto.Size(m)
+}
+func (m *MethodDescriptorProto) XXX_DiscardUnknown() {
+ xxx_messageInfo_MethodDescriptorProto.DiscardUnknown(m)
}
-func (m *MethodDescriptorProto) Reset() { *m = MethodDescriptorProto{} }
-func (m *MethodDescriptorProto) String() string { return proto.CompactTextString(m) }
-func (*MethodDescriptorProto) ProtoMessage() {}
-func (*MethodDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
+var xxx_messageInfo_MethodDescriptorProto proto.InternalMessageInfo
const Default_MethodDescriptorProto_ClientStreaming bool = false
const Default_MethodDescriptorProto_ServerStreaming bool = false
@@ -946,7 +1321,7 @@ type FileOptions struct {
// top-level extensions defined in the file.
JavaMultipleFiles *bool `protobuf:"varint,10,opt,name=java_multiple_files,json=javaMultipleFiles,def=0" json:"java_multiple_files,omitempty"`
// This option does nothing.
- JavaGenerateEqualsAndHash *bool `protobuf:"varint,20,opt,name=java_generate_equals_and_hash,json=javaGenerateEqualsAndHash" json:"java_generate_equals_and_hash,omitempty"`
+ JavaGenerateEqualsAndHash *bool `protobuf:"varint,20,opt,name=java_generate_equals_and_hash,json=javaGenerateEqualsAndHash" json:"java_generate_equals_and_hash,omitempty"` // Deprecated: Do not use.
// If set true, then the Java2 code generator will generate code that
// throws an exception whenever an attempt is made to assign a non-UTF-8
// byte sequence to a string field.
@@ -974,6 +1349,7 @@ type FileOptions struct {
CcGenericServices *bool `protobuf:"varint,16,opt,name=cc_generic_services,json=ccGenericServices,def=0" json:"cc_generic_services,omitempty"`
JavaGenericServices *bool `protobuf:"varint,17,opt,name=java_generic_services,json=javaGenericServices,def=0" json:"java_generic_services,omitempty"`
PyGenericServices *bool `protobuf:"varint,18,opt,name=py_generic_services,json=pyGenericServices,def=0" json:"py_generic_services,omitempty"`
+ PhpGenericServices *bool `protobuf:"varint,42,opt,name=php_generic_services,json=phpGenericServices,def=0" json:"php_generic_services,omitempty"`
// Is this file deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for everything in the file, or it will be completely ignored; in the very
@@ -995,31 +1371,67 @@ type FileOptions struct {
// Sets the php class prefix which is prepended to all php generated classes
// from this .proto. Default is empty.
PhpClassPrefix *string `protobuf:"bytes,40,opt,name=php_class_prefix,json=phpClassPrefix" json:"php_class_prefix,omitempty"`
- // The parser stores options it doesn't recognize here. See above.
+ // Use this option to change the namespace of php generated classes. Default
+ // is empty. When this option is empty, the package name will be used for
+ // determining the namespace.
+ PhpNamespace *string `protobuf:"bytes,41,opt,name=php_namespace,json=phpNamespace" json:"php_namespace,omitempty"`
+ // Use this option to change the namespace of php generated metadata classes.
+ // Default is empty. When this option is empty, the proto file name will be used
+ // for determining the namespace.
+ PhpMetadataNamespace *string `protobuf:"bytes,44,opt,name=php_metadata_namespace,json=phpMetadataNamespace" json:"php_metadata_namespace,omitempty"`
+ // Use this option to change the package of ruby generated classes. Default
+ // is empty. When this option is not set, the package name will be used for
+ // determining the ruby package.
+ RubyPackage *string `protobuf:"bytes,45,opt,name=ruby_package,json=rubyPackage" json:"ruby_package,omitempty"`
+ // The parser stores options it doesn't recognize here.
+ // See the documentation for the "Options" section above.
UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
proto.XXX_InternalExtensions `json:"-"`
XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
-func (m *FileOptions) Reset() { *m = FileOptions{} }
-func (m *FileOptions) String() string { return proto.CompactTextString(m) }
-func (*FileOptions) ProtoMessage() {}
-func (*FileOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
+func (m *FileOptions) Reset() { *m = FileOptions{} }
+func (m *FileOptions) String() string { return proto.CompactTextString(m) }
+func (*FileOptions) ProtoMessage() {}
+func (*FileOptions) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{10}
+}
var extRange_FileOptions = []proto.ExtensionRange{
- {1000, 536870911},
+ {Start: 1000, End: 536870911},
}
func (*FileOptions) ExtensionRangeArray() []proto.ExtensionRange {
return extRange_FileOptions
}
+func (m *FileOptions) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_FileOptions.Unmarshal(m, b)
+}
+func (m *FileOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_FileOptions.Marshal(b, m, deterministic)
+}
+func (m *FileOptions) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_FileOptions.Merge(m, src)
+}
+func (m *FileOptions) XXX_Size() int {
+ return xxx_messageInfo_FileOptions.Size(m)
+}
+func (m *FileOptions) XXX_DiscardUnknown() {
+ xxx_messageInfo_FileOptions.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_FileOptions proto.InternalMessageInfo
+
const Default_FileOptions_JavaMultipleFiles bool = false
const Default_FileOptions_JavaStringCheckUtf8 bool = false
const Default_FileOptions_OptimizeFor FileOptions_OptimizeMode = FileOptions_SPEED
const Default_FileOptions_CcGenericServices bool = false
const Default_FileOptions_JavaGenericServices bool = false
const Default_FileOptions_PyGenericServices bool = false
+const Default_FileOptions_PhpGenericServices bool = false
const Default_FileOptions_Deprecated bool = false
const Default_FileOptions_CcEnableArenas bool = false
@@ -1044,6 +1456,7 @@ func (m *FileOptions) GetJavaMultipleFiles() bool {
return Default_FileOptions_JavaMultipleFiles
}
+// Deprecated: Do not use.
func (m *FileOptions) GetJavaGenerateEqualsAndHash() bool {
if m != nil && m.JavaGenerateEqualsAndHash != nil {
return *m.JavaGenerateEqualsAndHash
@@ -1093,6 +1506,13 @@ func (m *FileOptions) GetPyGenericServices() bool {
return Default_FileOptions_PyGenericServices
}
+func (m *FileOptions) GetPhpGenericServices() bool {
+ if m != nil && m.PhpGenericServices != nil {
+ return *m.PhpGenericServices
+ }
+ return Default_FileOptions_PhpGenericServices
+}
+
func (m *FileOptions) GetDeprecated() bool {
if m != nil && m.Deprecated != nil {
return *m.Deprecated
@@ -1135,6 +1555,27 @@ func (m *FileOptions) GetPhpClassPrefix() string {
return ""
}
+func (m *FileOptions) GetPhpNamespace() string {
+ if m != nil && m.PhpNamespace != nil {
+ return *m.PhpNamespace
+ }
+ return ""
+}
+
+func (m *FileOptions) GetPhpMetadataNamespace() string {
+ if m != nil && m.PhpMetadataNamespace != nil {
+ return *m.PhpMetadataNamespace
+ }
+ return ""
+}
+
+func (m *FileOptions) GetRubyPackage() string {
+ if m != nil && m.RubyPackage != nil {
+ return *m.RubyPackage
+ }
+ return ""
+}
+
func (m *FileOptions) GetUninterpretedOption() []*UninterpretedOption {
if m != nil {
return m.UninterpretedOption
@@ -1195,23 +1636,45 @@ type MessageOptions struct {
MapEntry *bool `protobuf:"varint,7,opt,name=map_entry,json=mapEntry" json:"map_entry,omitempty"`
// The parser stores options it doesn't recognize here. See above.
UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
proto.XXX_InternalExtensions `json:"-"`
XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
-func (m *MessageOptions) Reset() { *m = MessageOptions{} }
-func (m *MessageOptions) String() string { return proto.CompactTextString(m) }
-func (*MessageOptions) ProtoMessage() {}
-func (*MessageOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
+func (m *MessageOptions) Reset() { *m = MessageOptions{} }
+func (m *MessageOptions) String() string { return proto.CompactTextString(m) }
+func (*MessageOptions) ProtoMessage() {}
+func (*MessageOptions) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{11}
+}
var extRange_MessageOptions = []proto.ExtensionRange{
- {1000, 536870911},
+ {Start: 1000, End: 536870911},
}
func (*MessageOptions) ExtensionRangeArray() []proto.ExtensionRange {
return extRange_MessageOptions
}
+func (m *MessageOptions) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_MessageOptions.Unmarshal(m, b)
+}
+func (m *MessageOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_MessageOptions.Marshal(b, m, deterministic)
+}
+func (m *MessageOptions) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MessageOptions.Merge(m, src)
+}
+func (m *MessageOptions) XXX_Size() int {
+ return xxx_messageInfo_MessageOptions.Size(m)
+}
+func (m *MessageOptions) XXX_DiscardUnknown() {
+ xxx_messageInfo_MessageOptions.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MessageOptions proto.InternalMessageInfo
+
const Default_MessageOptions_MessageSetWireFormat bool = false
const Default_MessageOptions_NoStandardDescriptorAccessor bool = false
const Default_MessageOptions_Deprecated bool = false
@@ -1265,13 +1728,15 @@ type FieldOptions struct {
Packed *bool `protobuf:"varint,2,opt,name=packed" json:"packed,omitempty"`
// The jstype option determines the JavaScript type used for values of the
// field. The option is permitted only for 64 bit integral and fixed types
- // (int64, uint64, sint64, fixed64, sfixed64). By default these types are
- // represented as JavaScript strings. This avoids loss of precision that can
- // happen when a large value is converted to a floating point JavaScript
- // numbers. Specifying JS_NUMBER for the jstype causes the generated
- // JavaScript code to use the JavaScript "number" type instead of strings.
- // This option is an enum to permit additional types to be added,
- // e.g. goog.math.Integer.
+ // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING
+ // is represented as JavaScript string, which avoids loss of precision that
+ // can happen when a large value is converted to a floating point JavaScript.
+ // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
+ // use the JavaScript "number" type. The behavior of the default option
+ // JS_NORMAL is implementation dependent.
+ //
+ // This option is an enum to permit additional types to be added, e.g.
+ // goog.math.Integer.
Jstype *FieldOptions_JSType `protobuf:"varint,6,opt,name=jstype,enum=google.protobuf.FieldOptions_JSType,def=0" json:"jstype,omitempty"`
// Should this field be parsed lazily? Lazy applies only to message-type
// fields. It means that when the outer message is initially parsed, the
@@ -1311,23 +1776,45 @@ type FieldOptions struct {
Weak *bool `protobuf:"varint,10,opt,name=weak,def=0" json:"weak,omitempty"`
// The parser stores options it doesn't recognize here. See above.
UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
proto.XXX_InternalExtensions `json:"-"`
XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
-func (m *FieldOptions) Reset() { *m = FieldOptions{} }
-func (m *FieldOptions) String() string { return proto.CompactTextString(m) }
-func (*FieldOptions) ProtoMessage() {}
-func (*FieldOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
+func (m *FieldOptions) Reset() { *m = FieldOptions{} }
+func (m *FieldOptions) String() string { return proto.CompactTextString(m) }
+func (*FieldOptions) ProtoMessage() {}
+func (*FieldOptions) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{12}
+}
var extRange_FieldOptions = []proto.ExtensionRange{
- {1000, 536870911},
+ {Start: 1000, End: 536870911},
}
func (*FieldOptions) ExtensionRangeArray() []proto.ExtensionRange {
return extRange_FieldOptions
}
+func (m *FieldOptions) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_FieldOptions.Unmarshal(m, b)
+}
+func (m *FieldOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_FieldOptions.Marshal(b, m, deterministic)
+}
+func (m *FieldOptions) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_FieldOptions.Merge(m, src)
+}
+func (m *FieldOptions) XXX_Size() int {
+ return xxx_messageInfo_FieldOptions.Size(m)
+}
+func (m *FieldOptions) XXX_DiscardUnknown() {
+ xxx_messageInfo_FieldOptions.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_FieldOptions proto.InternalMessageInfo
+
const Default_FieldOptions_Ctype FieldOptions_CType = FieldOptions_STRING
const Default_FieldOptions_Jstype FieldOptions_JSType = FieldOptions_JS_NORMAL
const Default_FieldOptions_Lazy bool = false
@@ -1386,23 +1873,45 @@ func (m *FieldOptions) GetUninterpretedOption() []*UninterpretedOption {
type OneofOptions struct {
// The parser stores options it doesn't recognize here. See above.
UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
proto.XXX_InternalExtensions `json:"-"`
XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
-func (m *OneofOptions) Reset() { *m = OneofOptions{} }
-func (m *OneofOptions) String() string { return proto.CompactTextString(m) }
-func (*OneofOptions) ProtoMessage() {}
-func (*OneofOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
+func (m *OneofOptions) Reset() { *m = OneofOptions{} }
+func (m *OneofOptions) String() string { return proto.CompactTextString(m) }
+func (*OneofOptions) ProtoMessage() {}
+func (*OneofOptions) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{13}
+}
var extRange_OneofOptions = []proto.ExtensionRange{
- {1000, 536870911},
+ {Start: 1000, End: 536870911},
}
func (*OneofOptions) ExtensionRangeArray() []proto.ExtensionRange {
return extRange_OneofOptions
}
+func (m *OneofOptions) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_OneofOptions.Unmarshal(m, b)
+}
+func (m *OneofOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_OneofOptions.Marshal(b, m, deterministic)
+}
+func (m *OneofOptions) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_OneofOptions.Merge(m, src)
+}
+func (m *OneofOptions) XXX_Size() int {
+ return xxx_messageInfo_OneofOptions.Size(m)
+}
+func (m *OneofOptions) XXX_DiscardUnknown() {
+ xxx_messageInfo_OneofOptions.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_OneofOptions proto.InternalMessageInfo
+
func (m *OneofOptions) GetUninterpretedOption() []*UninterpretedOption {
if m != nil {
return m.UninterpretedOption
@@ -1421,23 +1930,45 @@ type EnumOptions struct {
Deprecated *bool `protobuf:"varint,3,opt,name=deprecated,def=0" json:"deprecated,omitempty"`
// The parser stores options it doesn't recognize here. See above.
UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
proto.XXX_InternalExtensions `json:"-"`
XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
-func (m *EnumOptions) Reset() { *m = EnumOptions{} }
-func (m *EnumOptions) String() string { return proto.CompactTextString(m) }
-func (*EnumOptions) ProtoMessage() {}
-func (*EnumOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} }
+func (m *EnumOptions) Reset() { *m = EnumOptions{} }
+func (m *EnumOptions) String() string { return proto.CompactTextString(m) }
+func (*EnumOptions) ProtoMessage() {}
+func (*EnumOptions) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{14}
+}
var extRange_EnumOptions = []proto.ExtensionRange{
- {1000, 536870911},
+ {Start: 1000, End: 536870911},
}
func (*EnumOptions) ExtensionRangeArray() []proto.ExtensionRange {
return extRange_EnumOptions
}
+func (m *EnumOptions) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_EnumOptions.Unmarshal(m, b)
+}
+func (m *EnumOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_EnumOptions.Marshal(b, m, deterministic)
+}
+func (m *EnumOptions) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_EnumOptions.Merge(m, src)
+}
+func (m *EnumOptions) XXX_Size() int {
+ return xxx_messageInfo_EnumOptions.Size(m)
+}
+func (m *EnumOptions) XXX_DiscardUnknown() {
+ xxx_messageInfo_EnumOptions.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_EnumOptions proto.InternalMessageInfo
+
const Default_EnumOptions_Deprecated bool = false
func (m *EnumOptions) GetAllowAlias() bool {
@@ -1469,23 +2000,45 @@ type EnumValueOptions struct {
Deprecated *bool `protobuf:"varint,1,opt,name=deprecated,def=0" json:"deprecated,omitempty"`
// The parser stores options it doesn't recognize here. See above.
UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
proto.XXX_InternalExtensions `json:"-"`
XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
-func (m *EnumValueOptions) Reset() { *m = EnumValueOptions{} }
-func (m *EnumValueOptions) String() string { return proto.CompactTextString(m) }
-func (*EnumValueOptions) ProtoMessage() {}
-func (*EnumValueOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} }
+func (m *EnumValueOptions) Reset() { *m = EnumValueOptions{} }
+func (m *EnumValueOptions) String() string { return proto.CompactTextString(m) }
+func (*EnumValueOptions) ProtoMessage() {}
+func (*EnumValueOptions) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{15}
+}
var extRange_EnumValueOptions = []proto.ExtensionRange{
- {1000, 536870911},
+ {Start: 1000, End: 536870911},
}
func (*EnumValueOptions) ExtensionRangeArray() []proto.ExtensionRange {
return extRange_EnumValueOptions
}
+func (m *EnumValueOptions) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_EnumValueOptions.Unmarshal(m, b)
+}
+func (m *EnumValueOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_EnumValueOptions.Marshal(b, m, deterministic)
+}
+func (m *EnumValueOptions) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_EnumValueOptions.Merge(m, src)
+}
+func (m *EnumValueOptions) XXX_Size() int {
+ return xxx_messageInfo_EnumValueOptions.Size(m)
+}
+func (m *EnumValueOptions) XXX_DiscardUnknown() {
+ xxx_messageInfo_EnumValueOptions.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_EnumValueOptions proto.InternalMessageInfo
+
const Default_EnumValueOptions_Deprecated bool = false
func (m *EnumValueOptions) GetDeprecated() bool {
@@ -1510,23 +2063,45 @@ type ServiceOptions struct {
Deprecated *bool `protobuf:"varint,33,opt,name=deprecated,def=0" json:"deprecated,omitempty"`
// The parser stores options it doesn't recognize here. See above.
UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
proto.XXX_InternalExtensions `json:"-"`
XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
-func (m *ServiceOptions) Reset() { *m = ServiceOptions{} }
-func (m *ServiceOptions) String() string { return proto.CompactTextString(m) }
-func (*ServiceOptions) ProtoMessage() {}
-func (*ServiceOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} }
+func (m *ServiceOptions) Reset() { *m = ServiceOptions{} }
+func (m *ServiceOptions) String() string { return proto.CompactTextString(m) }
+func (*ServiceOptions) ProtoMessage() {}
+func (*ServiceOptions) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{16}
+}
var extRange_ServiceOptions = []proto.ExtensionRange{
- {1000, 536870911},
+ {Start: 1000, End: 536870911},
}
func (*ServiceOptions) ExtensionRangeArray() []proto.ExtensionRange {
return extRange_ServiceOptions
}
+func (m *ServiceOptions) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_ServiceOptions.Unmarshal(m, b)
+}
+func (m *ServiceOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_ServiceOptions.Marshal(b, m, deterministic)
+}
+func (m *ServiceOptions) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ServiceOptions.Merge(m, src)
+}
+func (m *ServiceOptions) XXX_Size() int {
+ return xxx_messageInfo_ServiceOptions.Size(m)
+}
+func (m *ServiceOptions) XXX_DiscardUnknown() {
+ xxx_messageInfo_ServiceOptions.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ServiceOptions proto.InternalMessageInfo
+
const Default_ServiceOptions_Deprecated bool = false
func (m *ServiceOptions) GetDeprecated() bool {
@@ -1552,23 +2127,45 @@ type MethodOptions struct {
IdempotencyLevel *MethodOptions_IdempotencyLevel `protobuf:"varint,34,opt,name=idempotency_level,json=idempotencyLevel,enum=google.protobuf.MethodOptions_IdempotencyLevel,def=0" json:"idempotency_level,omitempty"`
// The parser stores options it doesn't recognize here. See above.
UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
proto.XXX_InternalExtensions `json:"-"`
XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
-func (m *MethodOptions) Reset() { *m = MethodOptions{} }
-func (m *MethodOptions) String() string { return proto.CompactTextString(m) }
-func (*MethodOptions) ProtoMessage() {}
-func (*MethodOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} }
+func (m *MethodOptions) Reset() { *m = MethodOptions{} }
+func (m *MethodOptions) String() string { return proto.CompactTextString(m) }
+func (*MethodOptions) ProtoMessage() {}
+func (*MethodOptions) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{17}
+}
var extRange_MethodOptions = []proto.ExtensionRange{
- {1000, 536870911},
+ {Start: 1000, End: 536870911},
}
func (*MethodOptions) ExtensionRangeArray() []proto.ExtensionRange {
return extRange_MethodOptions
}
+func (m *MethodOptions) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_MethodOptions.Unmarshal(m, b)
+}
+func (m *MethodOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_MethodOptions.Marshal(b, m, deterministic)
+}
+func (m *MethodOptions) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MethodOptions.Merge(m, src)
+}
+func (m *MethodOptions) XXX_Size() int {
+ return xxx_messageInfo_MethodOptions.Size(m)
+}
+func (m *MethodOptions) XXX_DiscardUnknown() {
+ xxx_messageInfo_MethodOptions.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MethodOptions proto.InternalMessageInfo
+
const Default_MethodOptions_Deprecated bool = false
const Default_MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel = MethodOptions_IDEMPOTENCY_UNKNOWN
@@ -1603,19 +2200,41 @@ type UninterpretedOption struct {
Name []*UninterpretedOption_NamePart `protobuf:"bytes,2,rep,name=name" json:"name,omitempty"`
// The value of the uninterpreted option, in whatever type the tokenizer
// identified it as during parsing. Exactly one of these should be set.
- IdentifierValue *string `protobuf:"bytes,3,opt,name=identifier_value,json=identifierValue" json:"identifier_value,omitempty"`
- PositiveIntValue *uint64 `protobuf:"varint,4,opt,name=positive_int_value,json=positiveIntValue" json:"positive_int_value,omitempty"`
- NegativeIntValue *int64 `protobuf:"varint,5,opt,name=negative_int_value,json=negativeIntValue" json:"negative_int_value,omitempty"`
- DoubleValue *float64 `protobuf:"fixed64,6,opt,name=double_value,json=doubleValue" json:"double_value,omitempty"`
- StringValue []byte `protobuf:"bytes,7,opt,name=string_value,json=stringValue" json:"string_value,omitempty"`
- AggregateValue *string `protobuf:"bytes,8,opt,name=aggregate_value,json=aggregateValue" json:"aggregate_value,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ IdentifierValue *string `protobuf:"bytes,3,opt,name=identifier_value,json=identifierValue" json:"identifier_value,omitempty"`
+ PositiveIntValue *uint64 `protobuf:"varint,4,opt,name=positive_int_value,json=positiveIntValue" json:"positive_int_value,omitempty"`
+ NegativeIntValue *int64 `protobuf:"varint,5,opt,name=negative_int_value,json=negativeIntValue" json:"negative_int_value,omitempty"`
+ DoubleValue *float64 `protobuf:"fixed64,6,opt,name=double_value,json=doubleValue" json:"double_value,omitempty"`
+ StringValue []byte `protobuf:"bytes,7,opt,name=string_value,json=stringValue" json:"string_value,omitempty"`
+ AggregateValue *string `protobuf:"bytes,8,opt,name=aggregate_value,json=aggregateValue" json:"aggregate_value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *UninterpretedOption) Reset() { *m = UninterpretedOption{} }
+func (m *UninterpretedOption) String() string { return proto.CompactTextString(m) }
+func (*UninterpretedOption) ProtoMessage() {}
+func (*UninterpretedOption) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{18}
+}
+
+func (m *UninterpretedOption) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_UninterpretedOption.Unmarshal(m, b)
+}
+func (m *UninterpretedOption) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_UninterpretedOption.Marshal(b, m, deterministic)
+}
+func (m *UninterpretedOption) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_UninterpretedOption.Merge(m, src)
+}
+func (m *UninterpretedOption) XXX_Size() int {
+ return xxx_messageInfo_UninterpretedOption.Size(m)
+}
+func (m *UninterpretedOption) XXX_DiscardUnknown() {
+ xxx_messageInfo_UninterpretedOption.DiscardUnknown(m)
}
-func (m *UninterpretedOption) Reset() { *m = UninterpretedOption{} }
-func (m *UninterpretedOption) String() string { return proto.CompactTextString(m) }
-func (*UninterpretedOption) ProtoMessage() {}
-func (*UninterpretedOption) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} }
+var xxx_messageInfo_UninterpretedOption proto.InternalMessageInfo
func (m *UninterpretedOption) GetName() []*UninterpretedOption_NamePart {
if m != nil {
@@ -1672,18 +2291,38 @@ func (m *UninterpretedOption) GetAggregateValue() string {
// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
// "foo.(bar.baz).qux".
type UninterpretedOption_NamePart struct {
- NamePart *string `protobuf:"bytes,1,req,name=name_part,json=namePart" json:"name_part,omitempty"`
- IsExtension *bool `protobuf:"varint,2,req,name=is_extension,json=isExtension" json:"is_extension,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ NamePart *string `protobuf:"bytes,1,req,name=name_part,json=namePart" json:"name_part,omitempty"`
+ IsExtension *bool `protobuf:"varint,2,req,name=is_extension,json=isExtension" json:"is_extension,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
func (m *UninterpretedOption_NamePart) Reset() { *m = UninterpretedOption_NamePart{} }
func (m *UninterpretedOption_NamePart) String() string { return proto.CompactTextString(m) }
func (*UninterpretedOption_NamePart) ProtoMessage() {}
func (*UninterpretedOption_NamePart) Descriptor() ([]byte, []int) {
- return fileDescriptor0, []int{17, 0}
+ return fileDescriptor_e5baabe45344a177, []int{18, 0}
}
+func (m *UninterpretedOption_NamePart) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_UninterpretedOption_NamePart.Unmarshal(m, b)
+}
+func (m *UninterpretedOption_NamePart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_UninterpretedOption_NamePart.Marshal(b, m, deterministic)
+}
+func (m *UninterpretedOption_NamePart) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_UninterpretedOption_NamePart.Merge(m, src)
+}
+func (m *UninterpretedOption_NamePart) XXX_Size() int {
+ return xxx_messageInfo_UninterpretedOption_NamePart.Size(m)
+}
+func (m *UninterpretedOption_NamePart) XXX_DiscardUnknown() {
+ xxx_messageInfo_UninterpretedOption_NamePart.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_UninterpretedOption_NamePart proto.InternalMessageInfo
+
func (m *UninterpretedOption_NamePart) GetNamePart() string {
if m != nil && m.NamePart != nil {
return *m.NamePart
@@ -1744,14 +2383,36 @@ type SourceCodeInfo struct {
// - Code which tries to interpret locations should probably be designed to
// ignore those that it doesn't understand, as more types of locations could
// be recorded in the future.
- Location []*SourceCodeInfo_Location `protobuf:"bytes,1,rep,name=location" json:"location,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ Location []*SourceCodeInfo_Location `protobuf:"bytes,1,rep,name=location" json:"location,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *SourceCodeInfo) Reset() { *m = SourceCodeInfo{} }
+func (m *SourceCodeInfo) String() string { return proto.CompactTextString(m) }
+func (*SourceCodeInfo) ProtoMessage() {}
+func (*SourceCodeInfo) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{19}
+}
+
+func (m *SourceCodeInfo) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_SourceCodeInfo.Unmarshal(m, b)
+}
+func (m *SourceCodeInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_SourceCodeInfo.Marshal(b, m, deterministic)
+}
+func (m *SourceCodeInfo) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_SourceCodeInfo.Merge(m, src)
+}
+func (m *SourceCodeInfo) XXX_Size() int {
+ return xxx_messageInfo_SourceCodeInfo.Size(m)
+}
+func (m *SourceCodeInfo) XXX_DiscardUnknown() {
+ xxx_messageInfo_SourceCodeInfo.DiscardUnknown(m)
}
-func (m *SourceCodeInfo) Reset() { *m = SourceCodeInfo{} }
-func (m *SourceCodeInfo) String() string { return proto.CompactTextString(m) }
-func (*SourceCodeInfo) ProtoMessage() {}
-func (*SourceCodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} }
+var xxx_messageInfo_SourceCodeInfo proto.InternalMessageInfo
func (m *SourceCodeInfo) GetLocation() []*SourceCodeInfo_Location {
if m != nil {
@@ -1841,13 +2502,35 @@ type SourceCodeInfo_Location struct {
LeadingComments *string `protobuf:"bytes,3,opt,name=leading_comments,json=leadingComments" json:"leading_comments,omitempty"`
TrailingComments *string `protobuf:"bytes,4,opt,name=trailing_comments,json=trailingComments" json:"trailing_comments,omitempty"`
LeadingDetachedComments []string `protobuf:"bytes,6,rep,name=leading_detached_comments,json=leadingDetachedComments" json:"leading_detached_comments,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *SourceCodeInfo_Location) Reset() { *m = SourceCodeInfo_Location{} }
+func (m *SourceCodeInfo_Location) String() string { return proto.CompactTextString(m) }
+func (*SourceCodeInfo_Location) ProtoMessage() {}
+func (*SourceCodeInfo_Location) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{19, 0}
+}
+
+func (m *SourceCodeInfo_Location) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_SourceCodeInfo_Location.Unmarshal(m, b)
+}
+func (m *SourceCodeInfo_Location) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_SourceCodeInfo_Location.Marshal(b, m, deterministic)
+}
+func (m *SourceCodeInfo_Location) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_SourceCodeInfo_Location.Merge(m, src)
+}
+func (m *SourceCodeInfo_Location) XXX_Size() int {
+ return xxx_messageInfo_SourceCodeInfo_Location.Size(m)
+}
+func (m *SourceCodeInfo_Location) XXX_DiscardUnknown() {
+ xxx_messageInfo_SourceCodeInfo_Location.DiscardUnknown(m)
}
-func (m *SourceCodeInfo_Location) Reset() { *m = SourceCodeInfo_Location{} }
-func (m *SourceCodeInfo_Location) String() string { return proto.CompactTextString(m) }
-func (*SourceCodeInfo_Location) ProtoMessage() {}
-func (*SourceCodeInfo_Location) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18, 0} }
+var xxx_messageInfo_SourceCodeInfo_Location proto.InternalMessageInfo
func (m *SourceCodeInfo_Location) GetPath() []int32 {
if m != nil {
@@ -1890,14 +2573,36 @@ func (m *SourceCodeInfo_Location) GetLeadingDetachedComments() []string {
type GeneratedCodeInfo struct {
// An Annotation connects some span of text in generated code to an element
// of its generating .proto file.
- Annotation []*GeneratedCodeInfo_Annotation `protobuf:"bytes,1,rep,name=annotation" json:"annotation,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ Annotation []*GeneratedCodeInfo_Annotation `protobuf:"bytes,1,rep,name=annotation" json:"annotation,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *GeneratedCodeInfo) Reset() { *m = GeneratedCodeInfo{} }
+func (m *GeneratedCodeInfo) String() string { return proto.CompactTextString(m) }
+func (*GeneratedCodeInfo) ProtoMessage() {}
+func (*GeneratedCodeInfo) Descriptor() ([]byte, []int) {
+ return fileDescriptor_e5baabe45344a177, []int{20}
+}
+
+func (m *GeneratedCodeInfo) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_GeneratedCodeInfo.Unmarshal(m, b)
+}
+func (m *GeneratedCodeInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_GeneratedCodeInfo.Marshal(b, m, deterministic)
+}
+func (m *GeneratedCodeInfo) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_GeneratedCodeInfo.Merge(m, src)
+}
+func (m *GeneratedCodeInfo) XXX_Size() int {
+ return xxx_messageInfo_GeneratedCodeInfo.Size(m)
+}
+func (m *GeneratedCodeInfo) XXX_DiscardUnknown() {
+ xxx_messageInfo_GeneratedCodeInfo.DiscardUnknown(m)
}
-func (m *GeneratedCodeInfo) Reset() { *m = GeneratedCodeInfo{} }
-func (m *GeneratedCodeInfo) String() string { return proto.CompactTextString(m) }
-func (*GeneratedCodeInfo) ProtoMessage() {}
-func (*GeneratedCodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} }
+var xxx_messageInfo_GeneratedCodeInfo proto.InternalMessageInfo
func (m *GeneratedCodeInfo) GetAnnotation() []*GeneratedCodeInfo_Annotation {
if m != nil {
@@ -1918,16 +2623,36 @@ type GeneratedCodeInfo_Annotation struct {
// Identifies the ending offset in bytes in the generated code that
// relates to the identified offset. The end offset should be one past
// the last relevant byte (so the length of the text = end - begin).
- End *int32 `protobuf:"varint,4,opt,name=end" json:"end,omitempty"`
- XXX_unrecognized []byte `json:"-"`
+ End *int32 `protobuf:"varint,4,opt,name=end" json:"end,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
func (m *GeneratedCodeInfo_Annotation) Reset() { *m = GeneratedCodeInfo_Annotation{} }
func (m *GeneratedCodeInfo_Annotation) String() string { return proto.CompactTextString(m) }
func (*GeneratedCodeInfo_Annotation) ProtoMessage() {}
func (*GeneratedCodeInfo_Annotation) Descriptor() ([]byte, []int) {
- return fileDescriptor0, []int{19, 0}
+ return fileDescriptor_e5baabe45344a177, []int{20, 0}
+}
+
+func (m *GeneratedCodeInfo_Annotation) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_GeneratedCodeInfo_Annotation.Unmarshal(m, b)
+}
+func (m *GeneratedCodeInfo_Annotation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_GeneratedCodeInfo_Annotation.Marshal(b, m, deterministic)
+}
+func (m *GeneratedCodeInfo_Annotation) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_GeneratedCodeInfo_Annotation.Merge(m, src)
}
+func (m *GeneratedCodeInfo_Annotation) XXX_Size() int {
+ return xxx_messageInfo_GeneratedCodeInfo_Annotation.Size(m)
+}
+func (m *GeneratedCodeInfo_Annotation) XXX_DiscardUnknown() {
+ xxx_messageInfo_GeneratedCodeInfo_Annotation.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_GeneratedCodeInfo_Annotation proto.InternalMessageInfo
func (m *GeneratedCodeInfo_Annotation) GetPath() []int32 {
if m != nil {
@@ -1958,14 +2683,22 @@ func (m *GeneratedCodeInfo_Annotation) GetEnd() int32 {
}
func init() {
+ proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Type", FieldDescriptorProto_Type_name, FieldDescriptorProto_Type_value)
+ proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Label", FieldDescriptorProto_Label_name, FieldDescriptorProto_Label_value)
+ proto.RegisterEnum("google.protobuf.FileOptions_OptimizeMode", FileOptions_OptimizeMode_name, FileOptions_OptimizeMode_value)
+ proto.RegisterEnum("google.protobuf.FieldOptions_CType", FieldOptions_CType_name, FieldOptions_CType_value)
+ proto.RegisterEnum("google.protobuf.FieldOptions_JSType", FieldOptions_JSType_name, FieldOptions_JSType_value)
+ proto.RegisterEnum("google.protobuf.MethodOptions_IdempotencyLevel", MethodOptions_IdempotencyLevel_name, MethodOptions_IdempotencyLevel_value)
proto.RegisterType((*FileDescriptorSet)(nil), "google.protobuf.FileDescriptorSet")
proto.RegisterType((*FileDescriptorProto)(nil), "google.protobuf.FileDescriptorProto")
proto.RegisterType((*DescriptorProto)(nil), "google.protobuf.DescriptorProto")
proto.RegisterType((*DescriptorProto_ExtensionRange)(nil), "google.protobuf.DescriptorProto.ExtensionRange")
proto.RegisterType((*DescriptorProto_ReservedRange)(nil), "google.protobuf.DescriptorProto.ReservedRange")
+ proto.RegisterType((*ExtensionRangeOptions)(nil), "google.protobuf.ExtensionRangeOptions")
proto.RegisterType((*FieldDescriptorProto)(nil), "google.protobuf.FieldDescriptorProto")
proto.RegisterType((*OneofDescriptorProto)(nil), "google.protobuf.OneofDescriptorProto")
proto.RegisterType((*EnumDescriptorProto)(nil), "google.protobuf.EnumDescriptorProto")
+ proto.RegisterType((*EnumDescriptorProto_EnumReservedRange)(nil), "google.protobuf.EnumDescriptorProto.EnumReservedRange")
proto.RegisterType((*EnumValueDescriptorProto)(nil), "google.protobuf.EnumValueDescriptorProto")
proto.RegisterType((*ServiceDescriptorProto)(nil), "google.protobuf.ServiceDescriptorProto")
proto.RegisterType((*MethodDescriptorProto)(nil), "google.protobuf.MethodDescriptorProto")
@@ -1983,170 +2716,172 @@ func init() {
proto.RegisterType((*SourceCodeInfo_Location)(nil), "google.protobuf.SourceCodeInfo.Location")
proto.RegisterType((*GeneratedCodeInfo)(nil), "google.protobuf.GeneratedCodeInfo")
proto.RegisterType((*GeneratedCodeInfo_Annotation)(nil), "google.protobuf.GeneratedCodeInfo.Annotation")
- proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Type", FieldDescriptorProto_Type_name, FieldDescriptorProto_Type_value)
- proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Label", FieldDescriptorProto_Label_name, FieldDescriptorProto_Label_value)
- proto.RegisterEnum("google.protobuf.FileOptions_OptimizeMode", FileOptions_OptimizeMode_name, FileOptions_OptimizeMode_value)
- proto.RegisterEnum("google.protobuf.FieldOptions_CType", FieldOptions_CType_name, FieldOptions_CType_value)
- proto.RegisterEnum("google.protobuf.FieldOptions_JSType", FieldOptions_JSType_name, FieldOptions_JSType_value)
- proto.RegisterEnum("google.protobuf.MethodOptions_IdempotencyLevel", MethodOptions_IdempotencyLevel_name, MethodOptions_IdempotencyLevel_value)
}
-func init() { proto.RegisterFile("google/protobuf/descriptor.proto", fileDescriptor0) }
-
-var fileDescriptor0 = []byte{
- // 2460 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0x5b, 0x6f, 0xdb, 0xc8,
- 0x15, 0x5e, 0x5d, 0x2d, 0x1d, 0xc9, 0xf2, 0x78, 0xec, 0x4d, 0x18, 0xef, 0x25, 0x8e, 0xf6, 0x12,
- 0x6f, 0xd2, 0xc8, 0x0b, 0xe7, 0xb2, 0x59, 0xa7, 0x48, 0x21, 0x4b, 0x8c, 0x57, 0xa9, 0x2c, 0xa9,
- 0x94, 0xdc, 0x4d, 0xf6, 0x85, 0x18, 0x93, 0x23, 0x99, 0x09, 0x45, 0x72, 0x49, 0x2a, 0x89, 0xf7,
- 0x29, 0x40, 0x9f, 0x0a, 0xf4, 0x07, 0x14, 0x45, 0xd1, 0x87, 0x7d, 0x59, 0xa0, 0x3f, 0xa0, 0xcf,
- 0xfd, 0x05, 0x05, 0xf6, 0xb9, 0x2f, 0x45, 0x51, 0xa0, 0xfd, 0x07, 0x7d, 0x2d, 0x66, 0x86, 0xa4,
- 0x48, 0x5d, 0x12, 0x77, 0x81, 0xec, 0x3e, 0xd9, 0x73, 0xce, 0x77, 0x0e, 0xcf, 0x9c, 0xf9, 0x66,
- 0xce, 0x99, 0x11, 0x6c, 0x8f, 0x6c, 0x7b, 0x64, 0xd2, 0x5d, 0xc7, 0xb5, 0x7d, 0xfb, 0x64, 0x32,
- 0xdc, 0xd5, 0xa9, 0xa7, 0xb9, 0x86, 0xe3, 0xdb, 0x6e, 0x8d, 0xcb, 0xf0, 0x9a, 0x40, 0xd4, 0x42,
- 0x44, 0xf5, 0x08, 0xd6, 0x1f, 0x18, 0x26, 0x6d, 0x46, 0xc0, 0x3e, 0xf5, 0xf1, 0x5d, 0xc8, 0x0e,
- 0x0d, 0x93, 0x4a, 0xa9, 0xed, 0xcc, 0x4e, 0x69, 0xef, 0xc3, 0xda, 0x8c, 0x51, 0x2d, 0x69, 0xd1,
- 0x63, 0x62, 0x85, 0x5b, 0x54, 0xff, 0x95, 0x85, 0x8d, 0x05, 0x5a, 0x8c, 0x21, 0x6b, 0x91, 0x31,
- 0xf3, 0x98, 0xda, 0x29, 0x2a, 0xfc, 0x7f, 0x2c, 0xc1, 0x8a, 0x43, 0xb4, 0xa7, 0x64, 0x44, 0xa5,
- 0x34, 0x17, 0x87, 0x43, 0xfc, 0x3e, 0x80, 0x4e, 0x1d, 0x6a, 0xe9, 0xd4, 0xd2, 0xce, 0xa4, 0xcc,
- 0x76, 0x66, 0xa7, 0xa8, 0xc4, 0x24, 0xf8, 0x3a, 0xac, 0x3b, 0x93, 0x13, 0xd3, 0xd0, 0xd4, 0x18,
- 0x0c, 0xb6, 0x33, 0x3b, 0x39, 0x05, 0x09, 0x45, 0x73, 0x0a, 0xbe, 0x0a, 0x6b, 0xcf, 0x29, 0x79,
- 0x1a, 0x87, 0x96, 0x38, 0xb4, 0xc2, 0xc4, 0x31, 0x60, 0x03, 0xca, 0x63, 0xea, 0x79, 0x64, 0x44,
- 0x55, 0xff, 0xcc, 0xa1, 0x52, 0x96, 0xcf, 0x7e, 0x7b, 0x6e, 0xf6, 0xb3, 0x33, 0x2f, 0x05, 0x56,
- 0x83, 0x33, 0x87, 0xe2, 0x3a, 0x14, 0xa9, 0x35, 0x19, 0x0b, 0x0f, 0xb9, 0x25, 0xf9, 0x93, 0xad,
- 0xc9, 0x78, 0xd6, 0x4b, 0x81, 0x99, 0x05, 0x2e, 0x56, 0x3c, 0xea, 0x3e, 0x33, 0x34, 0x2a, 0xe5,
- 0xb9, 0x83, 0xab, 0x73, 0x0e, 0xfa, 0x42, 0x3f, 0xeb, 0x23, 0xb4, 0xc3, 0x0d, 0x28, 0xd2, 0x17,
- 0x3e, 0xb5, 0x3c, 0xc3, 0xb6, 0xa4, 0x15, 0xee, 0xe4, 0xa3, 0x05, 0xab, 0x48, 0x4d, 0x7d, 0xd6,
- 0xc5, 0xd4, 0x0e, 0xdf, 0x81, 0x15, 0xdb, 0xf1, 0x0d, 0xdb, 0xf2, 0xa4, 0xc2, 0x76, 0x6a, 0xa7,
- 0xb4, 0xf7, 0xee, 0x42, 0x22, 0x74, 0x05, 0x46, 0x09, 0xc1, 0xb8, 0x05, 0xc8, 0xb3, 0x27, 0xae,
- 0x46, 0x55, 0xcd, 0xd6, 0xa9, 0x6a, 0x58, 0x43, 0x5b, 0x2a, 0x72, 0x07, 0x97, 0xe7, 0x27, 0xc2,
- 0x81, 0x0d, 0x5b, 0xa7, 0x2d, 0x6b, 0x68, 0x2b, 0x15, 0x2f, 0x31, 0xc6, 0x17, 0x20, 0xef, 0x9d,
- 0x59, 0x3e, 0x79, 0x21, 0x95, 0x39, 0x43, 0x82, 0x51, 0xf5, 0xbf, 0x39, 0x58, 0x3b, 0x0f, 0xc5,
- 0xee, 0x41, 0x6e, 0xc8, 0x66, 0x29, 0xa5, 0xff, 0x9f, 0x1c, 0x08, 0x9b, 0x64, 0x12, 0xf3, 0x3f,
- 0x30, 0x89, 0x75, 0x28, 0x59, 0xd4, 0xf3, 0xa9, 0x2e, 0x18, 0x91, 0x39, 0x27, 0xa7, 0x40, 0x18,
- 0xcd, 0x53, 0x2a, 0xfb, 0x83, 0x28, 0xf5, 0x08, 0xd6, 0xa2, 0x90, 0x54, 0x97, 0x58, 0xa3, 0x90,
- 0x9b, 0xbb, 0xaf, 0x8b, 0xa4, 0x26, 0x87, 0x76, 0x0a, 0x33, 0x53, 0x2a, 0x34, 0x31, 0xc6, 0x4d,
- 0x00, 0xdb, 0xa2, 0xf6, 0x50, 0xd5, 0xa9, 0x66, 0x4a, 0x85, 0x25, 0x59, 0xea, 0x32, 0xc8, 0x5c,
- 0x96, 0x6c, 0x21, 0xd5, 0x4c, 0xfc, 0xf9, 0x94, 0x6a, 0x2b, 0x4b, 0x98, 0x72, 0x24, 0x36, 0xd9,
- 0x1c, 0xdb, 0x8e, 0xa1, 0xe2, 0x52, 0xc6, 0x7b, 0xaa, 0x07, 0x33, 0x2b, 0xf2, 0x20, 0x6a, 0xaf,
- 0x9d, 0x99, 0x12, 0x98, 0x89, 0x89, 0xad, 0xba, 0xf1, 0x21, 0xfe, 0x00, 0x22, 0x81, 0xca, 0x69,
- 0x05, 0xfc, 0x14, 0x2a, 0x87, 0xc2, 0x0e, 0x19, 0xd3, 0xad, 0xbb, 0x50, 0x49, 0xa6, 0x07, 0x6f,
- 0x42, 0xce, 0xf3, 0x89, 0xeb, 0x73, 0x16, 0xe6, 0x14, 0x31, 0xc0, 0x08, 0x32, 0xd4, 0xd2, 0xf9,
- 0x29, 0x97, 0x53, 0xd8, 0xbf, 0x5b, 0x9f, 0xc1, 0x6a, 0xe2, 0xf3, 0xe7, 0x35, 0xac, 0xfe, 0x3e,
- 0x0f, 0x9b, 0x8b, 0x38, 0xb7, 0x90, 0xfe, 0x17, 0x20, 0x6f, 0x4d, 0xc6, 0x27, 0xd4, 0x95, 0x32,
- 0xdc, 0x43, 0x30, 0xc2, 0x75, 0xc8, 0x99, 0xe4, 0x84, 0x9a, 0x52, 0x76, 0x3b, 0xb5, 0x53, 0xd9,
- 0xbb, 0x7e, 0x2e, 0x56, 0xd7, 0xda, 0xcc, 0x44, 0x11, 0x96, 0xf8, 0x3e, 0x64, 0x83, 0x23, 0x8e,
- 0x79, 0xb8, 0x76, 0x3e, 0x0f, 0x8c, 0x8b, 0x0a, 0xb7, 0xc3, 0xef, 0x40, 0x91, 0xfd, 0x15, 0xb9,
- 0xcd, 0xf3, 0x98, 0x0b, 0x4c, 0xc0, 0xf2, 0x8a, 0xb7, 0xa0, 0xc0, 0x69, 0xa6, 0xd3, 0xb0, 0x34,
- 0x44, 0x63, 0xb6, 0x30, 0x3a, 0x1d, 0x92, 0x89, 0xe9, 0xab, 0xcf, 0x88, 0x39, 0xa1, 0x9c, 0x30,
- 0x45, 0xa5, 0x1c, 0x08, 0x7f, 0xcd, 0x64, 0xf8, 0x32, 0x94, 0x04, 0x2b, 0x0d, 0x4b, 0xa7, 0x2f,
- 0xf8, 0xe9, 0x93, 0x53, 0x04, 0x51, 0x5b, 0x4c, 0xc2, 0x3e, 0xff, 0xc4, 0xb3, 0xad, 0x70, 0x69,
- 0xf9, 0x27, 0x98, 0x80, 0x7f, 0xfe, 0xb3, 0xd9, 0x83, 0xef, 0xbd, 0xc5, 0xd3, 0x9b, 0xe5, 0x62,
- 0xf5, 0x2f, 0x69, 0xc8, 0xf2, 0xfd, 0xb6, 0x06, 0xa5, 0xc1, 0xe3, 0x9e, 0xac, 0x36, 0xbb, 0xc7,
- 0x07, 0x6d, 0x19, 0xa5, 0x70, 0x05, 0x80, 0x0b, 0x1e, 0xb4, 0xbb, 0xf5, 0x01, 0x4a, 0x47, 0xe3,
- 0x56, 0x67, 0x70, 0xe7, 0x16, 0xca, 0x44, 0x06, 0xc7, 0x42, 0x90, 0x8d, 0x03, 0x6e, 0xee, 0xa1,
- 0x1c, 0x46, 0x50, 0x16, 0x0e, 0x5a, 0x8f, 0xe4, 0xe6, 0x9d, 0x5b, 0x28, 0x9f, 0x94, 0xdc, 0xdc,
- 0x43, 0x2b, 0x78, 0x15, 0x8a, 0x5c, 0x72, 0xd0, 0xed, 0xb6, 0x51, 0x21, 0xf2, 0xd9, 0x1f, 0x28,
- 0xad, 0xce, 0x21, 0x2a, 0x46, 0x3e, 0x0f, 0x95, 0xee, 0x71, 0x0f, 0x41, 0xe4, 0xe1, 0x48, 0xee,
- 0xf7, 0xeb, 0x87, 0x32, 0x2a, 0x45, 0x88, 0x83, 0xc7, 0x03, 0xb9, 0x8f, 0xca, 0x89, 0xb0, 0x6e,
- 0xee, 0xa1, 0xd5, 0xe8, 0x13, 0x72, 0xe7, 0xf8, 0x08, 0x55, 0xf0, 0x3a, 0xac, 0x8a, 0x4f, 0x84,
- 0x41, 0xac, 0xcd, 0x88, 0xee, 0xdc, 0x42, 0x68, 0x1a, 0x88, 0xf0, 0xb2, 0x9e, 0x10, 0xdc, 0xb9,
- 0x85, 0x70, 0xb5, 0x01, 0x39, 0xce, 0x2e, 0x8c, 0xa1, 0xd2, 0xae, 0x1f, 0xc8, 0x6d, 0xb5, 0xdb,
- 0x1b, 0xb4, 0xba, 0x9d, 0x7a, 0x1b, 0xa5, 0xa6, 0x32, 0x45, 0xfe, 0xd5, 0x71, 0x4b, 0x91, 0x9b,
- 0x28, 0x1d, 0x97, 0xf5, 0xe4, 0xfa, 0x40, 0x6e, 0xa2, 0x4c, 0x55, 0x83, 0xcd, 0x45, 0xe7, 0xcc,
- 0xc2, 0x9d, 0x11, 0x5b, 0xe2, 0xf4, 0x92, 0x25, 0xe6, 0xbe, 0xe6, 0x96, 0xf8, 0xdb, 0x14, 0x6c,
- 0x2c, 0x38, 0x6b, 0x17, 0x7e, 0xe4, 0x17, 0x90, 0x13, 0x14, 0x15, 0xd5, 0xe7, 0x93, 0x85, 0x87,
- 0x36, 0x27, 0xec, 0x5c, 0x05, 0xe2, 0x76, 0xf1, 0x0a, 0x9c, 0x59, 0x52, 0x81, 0x99, 0x8b, 0xb9,
- 0x20, 0x7f, 0x93, 0x02, 0x69, 0x99, 0xef, 0xd7, 0x1c, 0x14, 0xe9, 0xc4, 0x41, 0x71, 0x6f, 0x36,
- 0x80, 0x2b, 0xcb, 0xe7, 0x30, 0x17, 0xc5, 0x77, 0x29, 0xb8, 0xb0, 0xb8, 0x51, 0x59, 0x18, 0xc3,
- 0x7d, 0xc8, 0x8f, 0xa9, 0x7f, 0x6a, 0x87, 0xc5, 0xfa, 0xe3, 0x05, 0x25, 0x80, 0xa9, 0x67, 0x73,
- 0x15, 0x58, 0xc5, 0x6b, 0x48, 0x66, 0x59, 0xb7, 0x21, 0xa2, 0x99, 0x8b, 0xf4, 0xb7, 0x69, 0x78,
- 0x7b, 0xa1, 0xf3, 0x85, 0x81, 0xbe, 0x07, 0x60, 0x58, 0xce, 0xc4, 0x17, 0x05, 0x59, 0x9c, 0x4f,
- 0x45, 0x2e, 0xe1, 0x7b, 0x9f, 0x9d, 0x3d, 0x13, 0x3f, 0xd2, 0x67, 0xb8, 0x1e, 0x84, 0x88, 0x03,
- 0xee, 0x4e, 0x03, 0xcd, 0xf2, 0x40, 0xdf, 0x5f, 0x32, 0xd3, 0xb9, 0x5a, 0xf7, 0x29, 0x20, 0xcd,
- 0x34, 0xa8, 0xe5, 0xab, 0x9e, 0xef, 0x52, 0x32, 0x36, 0xac, 0x11, 0x3f, 0x80, 0x0b, 0xfb, 0xb9,
- 0x21, 0x31, 0x3d, 0xaa, 0xac, 0x09, 0x75, 0x3f, 0xd4, 0x32, 0x0b, 0x5e, 0x65, 0xdc, 0x98, 0x45,
- 0x3e, 0x61, 0x21, 0xd4, 0x91, 0x45, 0xf5, 0xef, 0x2b, 0x50, 0x8a, 0xb5, 0x75, 0xf8, 0x0a, 0x94,
- 0x9f, 0x90, 0x67, 0x44, 0x0d, 0x5b, 0x75, 0x91, 0x89, 0x12, 0x93, 0xf5, 0x82, 0x76, 0xfd, 0x53,
- 0xd8, 0xe4, 0x10, 0x7b, 0xe2, 0x53, 0x57, 0xd5, 0x4c, 0xe2, 0x79, 0x3c, 0x69, 0x05, 0x0e, 0xc5,
- 0x4c, 0xd7, 0x65, 0xaa, 0x46, 0xa8, 0xc1, 0xb7, 0x61, 0x83, 0x5b, 0x8c, 0x27, 0xa6, 0x6f, 0x38,
- 0x26, 0x55, 0xd9, 0xe5, 0xc1, 0xe3, 0x07, 0x71, 0x14, 0xd9, 0x3a, 0x43, 0x1c, 0x05, 0x00, 0x16,
- 0x91, 0x87, 0x9b, 0xf0, 0x1e, 0x37, 0x1b, 0x51, 0x8b, 0xba, 0xc4, 0xa7, 0x2a, 0xfd, 0x7a, 0x42,
- 0x4c, 0x4f, 0x25, 0x96, 0xae, 0x9e, 0x12, 0xef, 0x54, 0xda, 0x64, 0x0e, 0x0e, 0xd2, 0x52, 0x4a,
- 0xb9, 0xc4, 0x80, 0x87, 0x01, 0x4e, 0xe6, 0xb0, 0xba, 0xa5, 0x7f, 0x41, 0xbc, 0x53, 0xbc, 0x0f,
- 0x17, 0xb8, 0x17, 0xcf, 0x77, 0x0d, 0x6b, 0xa4, 0x6a, 0xa7, 0x54, 0x7b, 0xaa, 0x4e, 0xfc, 0xe1,
- 0x5d, 0xe9, 0x9d, 0xf8, 0xf7, 0x79, 0x84, 0x7d, 0x8e, 0x69, 0x30, 0xc8, 0xb1, 0x3f, 0xbc, 0x8b,
- 0xfb, 0x50, 0x66, 0x8b, 0x31, 0x36, 0xbe, 0xa1, 0xea, 0xd0, 0x76, 0x79, 0x65, 0xa9, 0x2c, 0xd8,
- 0xd9, 0xb1, 0x0c, 0xd6, 0xba, 0x81, 0xc1, 0x91, 0xad, 0xd3, 0xfd, 0x5c, 0xbf, 0x27, 0xcb, 0x4d,
- 0xa5, 0x14, 0x7a, 0x79, 0x60, 0xbb, 0x8c, 0x50, 0x23, 0x3b, 0x4a, 0x70, 0x49, 0x10, 0x6a, 0x64,
- 0x87, 0xe9, 0xbd, 0x0d, 0x1b, 0x9a, 0x26, 0xe6, 0x6c, 0x68, 0x6a, 0xd0, 0xe2, 0x7b, 0x12, 0x4a,
- 0x24, 0x4b, 0xd3, 0x0e, 0x05, 0x20, 0xe0, 0xb8, 0x87, 0x3f, 0x87, 0xb7, 0xa7, 0xc9, 0x8a, 0x1b,
- 0xae, 0xcf, 0xcd, 0x72, 0xd6, 0xf4, 0x36, 0x6c, 0x38, 0x67, 0xf3, 0x86, 0x38, 0xf1, 0x45, 0xe7,
- 0x6c, 0xd6, 0xec, 0x23, 0x7e, 0x6d, 0x73, 0xa9, 0x46, 0x7c, 0xaa, 0x4b, 0x17, 0xe3, 0xe8, 0x98,
- 0x02, 0xef, 0x02, 0xd2, 0x34, 0x95, 0x5a, 0xe4, 0xc4, 0xa4, 0x2a, 0x71, 0xa9, 0x45, 0x3c, 0xe9,
- 0x72, 0x1c, 0x5c, 0xd1, 0x34, 0x99, 0x6b, 0xeb, 0x5c, 0x89, 0xaf, 0xc1, 0xba, 0x7d, 0xf2, 0x44,
- 0x13, 0xcc, 0x52, 0x1d, 0x97, 0x0e, 0x8d, 0x17, 0xd2, 0x87, 0x3c, 0x4d, 0x6b, 0x4c, 0xc1, 0x79,
- 0xd5, 0xe3, 0x62, 0xfc, 0x09, 0x20, 0xcd, 0x3b, 0x25, 0xae, 0xc3, 0x4b, 0xbb, 0xe7, 0x10, 0x8d,
- 0x4a, 0x1f, 0x09, 0xa8, 0x90, 0x77, 0x42, 0x31, 0x63, 0xb6, 0xf7, 0xdc, 0x18, 0xfa, 0xa1, 0xc7,
- 0xab, 0x82, 0xd9, 0x5c, 0x16, 0x78, 0xdb, 0x01, 0xe4, 0x9c, 0x3a, 0xc9, 0x0f, 0xef, 0x70, 0x58,
- 0xc5, 0x39, 0x75, 0xe2, 0xdf, 0x7d, 0x04, 0x9b, 0x13, 0xcb, 0xb0, 0x7c, 0xea, 0x3a, 0x2e, 0x65,
- 0xed, 0xbe, 0xd8, 0xb3, 0xd2, 0xbf, 0x57, 0x96, 0x34, 0xec, 0xc7, 0x71, 0xb4, 0xa0, 0x8a, 0xb2,
- 0x31, 0x99, 0x17, 0x56, 0xf7, 0xa1, 0x1c, 0x67, 0x10, 0x2e, 0x82, 0xe0, 0x10, 0x4a, 0xb1, 0x6a,
- 0xdc, 0xe8, 0x36, 0x59, 0x1d, 0xfd, 0x4a, 0x46, 0x69, 0x56, 0xcf, 0xdb, 0xad, 0x81, 0xac, 0x2a,
- 0xc7, 0x9d, 0x41, 0xeb, 0x48, 0x46, 0x99, 0x6b, 0xc5, 0xc2, 0x7f, 0x56, 0xd0, 0xcb, 0x97, 0x2f,
- 0x5f, 0xa6, 0x1f, 0x66, 0x0b, 0x1f, 0xa3, 0xab, 0xd5, 0xef, 0xd3, 0x50, 0x49, 0x76, 0xd2, 0xf8,
- 0xe7, 0x70, 0x31, 0xbc, 0xf6, 0x7a, 0xd4, 0x57, 0x9f, 0x1b, 0x2e, 0xa7, 0xf6, 0x98, 0x88, 0x5e,
- 0x34, 0x5a, 0x95, 0xcd, 0x00, 0xd5, 0xa7, 0xfe, 0x97, 0x86, 0xcb, 0x88, 0x3b, 0x26, 0x3e, 0x6e,
- 0xc3, 0x65, 0xcb, 0x56, 0x3d, 0x9f, 0x58, 0x3a, 0x71, 0x75, 0x75, 0xfa, 0xe0, 0xa0, 0x12, 0x4d,
- 0xa3, 0x9e, 0x67, 0x8b, 0x92, 0x12, 0x79, 0x79, 0xd7, 0xb2, 0xfb, 0x01, 0x78, 0x7a, 0xd6, 0xd6,
- 0x03, 0xe8, 0x0c, 0x83, 0x32, 0xcb, 0x18, 0xf4, 0x0e, 0x14, 0xc7, 0xc4, 0x51, 0xa9, 0xe5, 0xbb,
- 0x67, 0xbc, 0xff, 0x2b, 0x28, 0x85, 0x31, 0x71, 0x64, 0x36, 0x7e, 0x73, 0x2b, 0x91, 0xcc, 0x66,
- 0x01, 0x15, 0x1f, 0x66, 0x0b, 0x45, 0x04, 0xd5, 0x7f, 0x66, 0xa0, 0x1c, 0xef, 0x07, 0x59, 0x7b,
- 0xad, 0xf1, 0xb3, 0x3f, 0xc5, 0x4f, 0x87, 0x0f, 0x5e, 0xd9, 0x3d, 0xd6, 0x1a, 0xac, 0x28, 0xec,
- 0xe7, 0x45, 0x97, 0xa6, 0x08, 0x4b, 0x56, 0x90, 0xd9, 0x79, 0x40, 0x45, 0xef, 0x5f, 0x50, 0x82,
- 0x11, 0x3e, 0x84, 0xfc, 0x13, 0x8f, 0xfb, 0xce, 0x73, 0xdf, 0x1f, 0xbe, 0xda, 0xf7, 0xc3, 0x3e,
- 0x77, 0x5e, 0x7c, 0xd8, 0x57, 0x3b, 0x5d, 0xe5, 0xa8, 0xde, 0x56, 0x02, 0x73, 0x7c, 0x09, 0xb2,
- 0x26, 0xf9, 0xe6, 0x2c, 0x59, 0x3e, 0xb8, 0xe8, 0xbc, 0x8b, 0x70, 0x09, 0xb2, 0xcf, 0x29, 0x79,
- 0x9a, 0x3c, 0xb4, 0xb9, 0xe8, 0x0d, 0x6e, 0x86, 0x5d, 0xc8, 0xf1, 0x7c, 0x61, 0x80, 0x20, 0x63,
- 0xe8, 0x2d, 0x5c, 0x80, 0x6c, 0xa3, 0xab, 0xb0, 0x0d, 0x81, 0xa0, 0x2c, 0xa4, 0x6a, 0xaf, 0x25,
- 0x37, 0x64, 0x94, 0xae, 0xde, 0x86, 0xbc, 0x48, 0x02, 0xdb, 0x2c, 0x51, 0x1a, 0xd0, 0x5b, 0xc1,
- 0x30, 0xf0, 0x91, 0x0a, 0xb5, 0xc7, 0x47, 0x07, 0xb2, 0x82, 0xd2, 0xc9, 0xa5, 0xce, 0xa2, 0x5c,
- 0xd5, 0x83, 0x72, 0xbc, 0x21, 0xfc, 0x51, 0x58, 0x56, 0xfd, 0x6b, 0x0a, 0x4a, 0xb1, 0x06, 0x8f,
- 0xb5, 0x16, 0xc4, 0x34, 0xed, 0xe7, 0x2a, 0x31, 0x0d, 0xe2, 0x05, 0xd4, 0x00, 0x2e, 0xaa, 0x33,
- 0xc9, 0x79, 0x97, 0xee, 0x47, 0xda, 0x22, 0x39, 0x94, 0xaf, 0xfe, 0x29, 0x05, 0x68, 0xb6, 0x45,
- 0x9c, 0x09, 0x33, 0xf5, 0x53, 0x86, 0x59, 0xfd, 0x63, 0x0a, 0x2a, 0xc9, 0xbe, 0x70, 0x26, 0xbc,
- 0x2b, 0x3f, 0x69, 0x78, 0xff, 0x48, 0xc3, 0x6a, 0xa2, 0x1b, 0x3c, 0x6f, 0x74, 0x5f, 0xc3, 0xba,
- 0xa1, 0xd3, 0xb1, 0x63, 0xfb, 0xd4, 0xd2, 0xce, 0x54, 0x93, 0x3e, 0xa3, 0xa6, 0x54, 0xe5, 0x87,
- 0xc6, 0xee, 0xab, 0xfb, 0xcd, 0x5a, 0x6b, 0x6a, 0xd7, 0x66, 0x66, 0xfb, 0x1b, 0xad, 0xa6, 0x7c,
- 0xd4, 0xeb, 0x0e, 0xe4, 0x4e, 0xe3, 0xb1, 0x7a, 0xdc, 0xf9, 0x65, 0xa7, 0xfb, 0x65, 0x47, 0x41,
- 0xc6, 0x0c, 0xec, 0x0d, 0x6e, 0xfb, 0x1e, 0xa0, 0xd9, 0xa0, 0xf0, 0x45, 0x58, 0x14, 0x16, 0x7a,
- 0x0b, 0x6f, 0xc0, 0x5a, 0xa7, 0xab, 0xf6, 0x5b, 0x4d, 0x59, 0x95, 0x1f, 0x3c, 0x90, 0x1b, 0x83,
- 0xbe, 0xb8, 0x80, 0x47, 0xe8, 0x41, 0x62, 0x83, 0x57, 0xff, 0x90, 0x81, 0x8d, 0x05, 0x91, 0xe0,
- 0x7a, 0xd0, 0xfb, 0x8b, 0xeb, 0xc8, 0x8d, 0xf3, 0x44, 0x5f, 0x63, 0xdd, 0x45, 0x8f, 0xb8, 0x7e,
- 0x70, 0x55, 0xf8, 0x04, 0x58, 0x96, 0x2c, 0xdf, 0x18, 0x1a, 0xd4, 0x0d, 0xde, 0x2b, 0xc4, 0x85,
- 0x60, 0x6d, 0x2a, 0x17, 0x4f, 0x16, 0x3f, 0x03, 0xec, 0xd8, 0x9e, 0xe1, 0x1b, 0xcf, 0xa8, 0x6a,
- 0x58, 0xe1, 0xe3, 0x06, 0xbb, 0x20, 0x64, 0x15, 0x14, 0x6a, 0x5a, 0x96, 0x1f, 0xa1, 0x2d, 0x3a,
- 0x22, 0x33, 0x68, 0x76, 0x98, 0x67, 0x14, 0x14, 0x6a, 0x22, 0xf4, 0x15, 0x28, 0xeb, 0xf6, 0x84,
- 0xb5, 0x5b, 0x02, 0xc7, 0x6a, 0x47, 0x4a, 0x29, 0x09, 0x59, 0x04, 0x09, 0xfa, 0xe1, 0xe9, 0xab,
- 0x4a, 0x59, 0x29, 0x09, 0x99, 0x80, 0x5c, 0x85, 0x35, 0x32, 0x1a, 0xb9, 0xcc, 0x79, 0xe8, 0x48,
- 0x74, 0xf8, 0x95, 0x48, 0xcc, 0x81, 0x5b, 0x0f, 0xa1, 0x10, 0xe6, 0x81, 0x95, 0x6a, 0x96, 0x09,
- 0xd5, 0x11, 0x6f, 0x5b, 0xe9, 0x9d, 0xa2, 0x52, 0xb0, 0x42, 0xe5, 0x15, 0x28, 0x1b, 0x9e, 0x3a,
- 0x7d, 0x64, 0x4d, 0x6f, 0xa7, 0x77, 0x0a, 0x4a, 0xc9, 0xf0, 0xa2, 0x57, 0xb5, 0xea, 0x77, 0x69,
- 0xa8, 0x24, 0x1f, 0x89, 0x71, 0x13, 0x0a, 0xa6, 0xad, 0x11, 0x4e, 0x2d, 0xf1, 0x0b, 0xc5, 0xce,
- 0x6b, 0xde, 0x95, 0x6b, 0xed, 0x00, 0xaf, 0x44, 0x96, 0x5b, 0x7f, 0x4b, 0x41, 0x21, 0x14, 0xe3,
- 0x0b, 0x90, 0x75, 0x88, 0x7f, 0xca, 0xdd, 0xe5, 0x0e, 0xd2, 0x28, 0xa5, 0xf0, 0x31, 0x93, 0x7b,
- 0x0e, 0xb1, 0x38, 0x05, 0x02, 0x39, 0x1b, 0xb3, 0x75, 0x35, 0x29, 0xd1, 0xf9, 0xf5, 0xc1, 0x1e,
- 0x8f, 0xa9, 0xe5, 0x7b, 0xe1, 0xba, 0x06, 0xf2, 0x46, 0x20, 0xc6, 0xd7, 0x61, 0xdd, 0x77, 0x89,
- 0x61, 0x26, 0xb0, 0x59, 0x8e, 0x45, 0xa1, 0x22, 0x02, 0xef, 0xc3, 0xa5, 0xd0, 0xaf, 0x4e, 0x7d,
- 0xa2, 0x9d, 0x52, 0x7d, 0x6a, 0x94, 0xe7, 0x2f, 0x90, 0x17, 0x03, 0x40, 0x33, 0xd0, 0x87, 0xb6,
- 0xd5, 0xef, 0x53, 0xb0, 0x1e, 0x5e, 0x78, 0xf4, 0x28, 0x59, 0x47, 0x00, 0xc4, 0xb2, 0x6c, 0x3f,
- 0x9e, 0xae, 0x79, 0x2a, 0xcf, 0xd9, 0xd5, 0xea, 0x91, 0x91, 0x12, 0x73, 0xb0, 0x35, 0x06, 0x98,
- 0x6a, 0x96, 0xa6, 0xed, 0x32, 0x94, 0x82, 0x5f, 0x00, 0xf8, 0xcf, 0x48, 0xe2, 0x8a, 0x0c, 0x42,
- 0xc4, 0x6e, 0x46, 0x78, 0x13, 0x72, 0x27, 0x74, 0x64, 0x58, 0xc1, 0xbb, 0xa4, 0x18, 0x84, 0xaf,
- 0x9d, 0xd9, 0xe8, 0xb5, 0xf3, 0xe0, 0x77, 0x29, 0xd8, 0xd0, 0xec, 0xf1, 0x6c, 0xbc, 0x07, 0x68,
- 0xe6, 0x9e, 0xee, 0x7d, 0x91, 0xfa, 0xea, 0xfe, 0xc8, 0xf0, 0x4f, 0x27, 0x27, 0x35, 0xcd, 0x1e,
- 0xef, 0x8e, 0x6c, 0x93, 0x58, 0xa3, 0xe9, 0xef, 0x60, 0xfc, 0x1f, 0xed, 0xc6, 0x88, 0x5a, 0x37,
- 0x46, 0x76, 0xec, 0x57, 0xb1, 0x7b, 0xd3, 0x7f, 0xbf, 0x4d, 0x67, 0x0e, 0x7b, 0x07, 0x7f, 0x4e,
- 0x6f, 0x1d, 0x8a, 0x6f, 0xf5, 0xc2, 0xdc, 0x28, 0x74, 0x68, 0x52, 0x8d, 0xcd, 0xf7, 0x7f, 0x01,
- 0x00, 0x00, 0xff, 0xff, 0x8e, 0x54, 0xe7, 0xef, 0x60, 0x1b, 0x00, 0x00,
+func init() { proto.RegisterFile("google/protobuf/descriptor.proto", fileDescriptor_e5baabe45344a177) }
+
+var fileDescriptor_e5baabe45344a177 = []byte{
+ // 2589 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0xdd, 0x8e, 0xdb, 0xc6,
+ 0x15, 0x0e, 0xf5, 0xb7, 0xd2, 0x91, 0x56, 0x3b, 0x3b, 0xbb, 0xb1, 0xe9, 0xcd, 0x8f, 0xd7, 0xca,
+ 0x8f, 0xd7, 0x4e, 0xac, 0x0d, 0x1c, 0xdb, 0x71, 0xd6, 0x45, 0x5a, 0xad, 0x44, 0x6f, 0xe4, 0xee,
+ 0x4a, 0x2a, 0xa5, 0x6d, 0x7e, 0x80, 0x82, 0x98, 0x25, 0x47, 0x12, 0x6d, 0x8a, 0x64, 0x48, 0xca,
+ 0xf6, 0x06, 0xbd, 0x30, 0xd0, 0xab, 0x5e, 0x15, 0xe8, 0x55, 0x51, 0x14, 0xbd, 0xe8, 0x4d, 0x80,
+ 0x3e, 0x40, 0x81, 0xde, 0xf5, 0x09, 0x0a, 0xe4, 0x0d, 0x8a, 0xb6, 0x40, 0xfb, 0x08, 0xbd, 0x2c,
+ 0x66, 0x86, 0xa4, 0x48, 0x49, 0x1b, 0x6f, 0x02, 0xc4, 0xb9, 0x92, 0xe6, 0x3b, 0xdf, 0x39, 0x73,
+ 0xe6, 0xcc, 0x99, 0x99, 0x33, 0x43, 0xd8, 0x1e, 0x39, 0xce, 0xc8, 0xa2, 0xbb, 0xae, 0xe7, 0x04,
+ 0xce, 0xc9, 0x74, 0xb8, 0x6b, 0x50, 0x5f, 0xf7, 0x4c, 0x37, 0x70, 0xbc, 0x3a, 0xc7, 0xf0, 0x9a,
+ 0x60, 0xd4, 0x23, 0x46, 0xed, 0x08, 0xd6, 0xef, 0x9b, 0x16, 0x6d, 0xc5, 0xc4, 0x3e, 0x0d, 0xf0,
+ 0x5d, 0xc8, 0x0d, 0x4d, 0x8b, 0xca, 0xd2, 0x76, 0x76, 0xa7, 0x7c, 0xf3, 0xcd, 0xfa, 0x9c, 0x52,
+ 0x3d, 0xad, 0xd1, 0x63, 0xb0, 0xca, 0x35, 0x6a, 0xff, 0xce, 0xc1, 0xc6, 0x12, 0x29, 0xc6, 0x90,
+ 0xb3, 0xc9, 0x84, 0x59, 0x94, 0x76, 0x4a, 0x2a, 0xff, 0x8f, 0x65, 0x58, 0x71, 0x89, 0xfe, 0x88,
+ 0x8c, 0xa8, 0x9c, 0xe1, 0x70, 0xd4, 0xc4, 0xaf, 0x03, 0x18, 0xd4, 0xa5, 0xb6, 0x41, 0x6d, 0xfd,
+ 0x54, 0xce, 0x6e, 0x67, 0x77, 0x4a, 0x6a, 0x02, 0xc1, 0xef, 0xc0, 0xba, 0x3b, 0x3d, 0xb1, 0x4c,
+ 0x5d, 0x4b, 0xd0, 0x60, 0x3b, 0xbb, 0x93, 0x57, 0x91, 0x10, 0xb4, 0x66, 0xe4, 0xab, 0xb0, 0xf6,
+ 0x84, 0x92, 0x47, 0x49, 0x6a, 0x99, 0x53, 0xab, 0x0c, 0x4e, 0x10, 0x9b, 0x50, 0x99, 0x50, 0xdf,
+ 0x27, 0x23, 0xaa, 0x05, 0xa7, 0x2e, 0x95, 0x73, 0x7c, 0xf4, 0xdb, 0x0b, 0xa3, 0x9f, 0x1f, 0x79,
+ 0x39, 0xd4, 0x1a, 0x9c, 0xba, 0x14, 0x37, 0xa0, 0x44, 0xed, 0xe9, 0x44, 0x58, 0xc8, 0x9f, 0x11,
+ 0x3f, 0xc5, 0x9e, 0x4e, 0xe6, 0xad, 0x14, 0x99, 0x5a, 0x68, 0x62, 0xc5, 0xa7, 0xde, 0x63, 0x53,
+ 0xa7, 0x72, 0x81, 0x1b, 0xb8, 0xba, 0x60, 0xa0, 0x2f, 0xe4, 0xf3, 0x36, 0x22, 0x3d, 0xdc, 0x84,
+ 0x12, 0x7d, 0x1a, 0x50, 0xdb, 0x37, 0x1d, 0x5b, 0x5e, 0xe1, 0x46, 0xde, 0x5a, 0x32, 0x8b, 0xd4,
+ 0x32, 0xe6, 0x4d, 0xcc, 0xf4, 0xf0, 0x1d, 0x58, 0x71, 0xdc, 0xc0, 0x74, 0x6c, 0x5f, 0x2e, 0x6e,
+ 0x4b, 0x3b, 0xe5, 0x9b, 0xaf, 0x2e, 0x4d, 0x84, 0xae, 0xe0, 0xa8, 0x11, 0x19, 0xb7, 0x01, 0xf9,
+ 0xce, 0xd4, 0xd3, 0xa9, 0xa6, 0x3b, 0x06, 0xd5, 0x4c, 0x7b, 0xe8, 0xc8, 0x25, 0x6e, 0xe0, 0xf2,
+ 0xe2, 0x40, 0x38, 0xb1, 0xe9, 0x18, 0xb4, 0x6d, 0x0f, 0x1d, 0xb5, 0xea, 0xa7, 0xda, 0xf8, 0x02,
+ 0x14, 0xfc, 0x53, 0x3b, 0x20, 0x4f, 0xe5, 0x0a, 0xcf, 0x90, 0xb0, 0x55, 0xfb, 0x6b, 0x01, 0xd6,
+ 0xce, 0x93, 0x62, 0xf7, 0x20, 0x3f, 0x64, 0xa3, 0x94, 0x33, 0xdf, 0x26, 0x06, 0x42, 0x27, 0x1d,
+ 0xc4, 0xc2, 0x77, 0x0c, 0x62, 0x03, 0xca, 0x36, 0xf5, 0x03, 0x6a, 0x88, 0x8c, 0xc8, 0x9e, 0x33,
+ 0xa7, 0x40, 0x28, 0x2d, 0xa6, 0x54, 0xee, 0x3b, 0xa5, 0xd4, 0xa7, 0xb0, 0x16, 0xbb, 0xa4, 0x79,
+ 0xc4, 0x1e, 0x45, 0xb9, 0xb9, 0xfb, 0x3c, 0x4f, 0xea, 0x4a, 0xa4, 0xa7, 0x32, 0x35, 0xb5, 0x4a,
+ 0x53, 0x6d, 0xdc, 0x02, 0x70, 0x6c, 0xea, 0x0c, 0x35, 0x83, 0xea, 0x96, 0x5c, 0x3c, 0x23, 0x4a,
+ 0x5d, 0x46, 0x59, 0x88, 0x92, 0x23, 0x50, 0xdd, 0xc2, 0x1f, 0xce, 0x52, 0x6d, 0xe5, 0x8c, 0x4c,
+ 0x39, 0x12, 0x8b, 0x6c, 0x21, 0xdb, 0x8e, 0xa1, 0xea, 0x51, 0x96, 0xf7, 0xd4, 0x08, 0x47, 0x56,
+ 0xe2, 0x4e, 0xd4, 0x9f, 0x3b, 0x32, 0x35, 0x54, 0x13, 0x03, 0x5b, 0xf5, 0x92, 0x4d, 0xfc, 0x06,
+ 0xc4, 0x80, 0xc6, 0xd3, 0x0a, 0xf8, 0x2e, 0x54, 0x89, 0xc0, 0x0e, 0x99, 0xd0, 0xad, 0x2f, 0xa1,
+ 0x9a, 0x0e, 0x0f, 0xde, 0x84, 0xbc, 0x1f, 0x10, 0x2f, 0xe0, 0x59, 0x98, 0x57, 0x45, 0x03, 0x23,
+ 0xc8, 0x52, 0xdb, 0xe0, 0xbb, 0x5c, 0x5e, 0x65, 0x7f, 0xf1, 0x4f, 0x66, 0x03, 0xce, 0xf2, 0x01,
+ 0xbf, 0xbd, 0x38, 0xa3, 0x29, 0xcb, 0xf3, 0xe3, 0xde, 0xfa, 0x00, 0x56, 0x53, 0x03, 0x38, 0x6f,
+ 0xd7, 0xb5, 0x5f, 0xc2, 0xcb, 0x4b, 0x4d, 0xe3, 0x4f, 0x61, 0x73, 0x6a, 0x9b, 0x76, 0x40, 0x3d,
+ 0xd7, 0xa3, 0x2c, 0x63, 0x45, 0x57, 0xf2, 0x7f, 0x56, 0xce, 0xc8, 0xb9, 0xe3, 0x24, 0x5b, 0x58,
+ 0x51, 0x37, 0xa6, 0x8b, 0xe0, 0xf5, 0x52, 0xf1, 0xbf, 0x2b, 0xe8, 0xd9, 0xb3, 0x67, 0xcf, 0x32,
+ 0xb5, 0xdf, 0x15, 0x60, 0x73, 0xd9, 0x9a, 0x59, 0xba, 0x7c, 0x2f, 0x40, 0xc1, 0x9e, 0x4e, 0x4e,
+ 0xa8, 0xc7, 0x83, 0x94, 0x57, 0xc3, 0x16, 0x6e, 0x40, 0xde, 0x22, 0x27, 0xd4, 0x92, 0x73, 0xdb,
+ 0xd2, 0x4e, 0xf5, 0xe6, 0x3b, 0xe7, 0x5a, 0x95, 0xf5, 0x43, 0xa6, 0xa2, 0x0a, 0x4d, 0xfc, 0x11,
+ 0xe4, 0xc2, 0x2d, 0x9a, 0x59, 0xb8, 0x7e, 0x3e, 0x0b, 0x6c, 0x2d, 0xa9, 0x5c, 0x0f, 0xbf, 0x02,
+ 0x25, 0xf6, 0x2b, 0x72, 0xa3, 0xc0, 0x7d, 0x2e, 0x32, 0x80, 0xe5, 0x05, 0xde, 0x82, 0x22, 0x5f,
+ 0x26, 0x06, 0x8d, 0x8e, 0xb6, 0xb8, 0xcd, 0x12, 0xcb, 0xa0, 0x43, 0x32, 0xb5, 0x02, 0xed, 0x31,
+ 0xb1, 0xa6, 0x94, 0x27, 0x7c, 0x49, 0xad, 0x84, 0xe0, 0xcf, 0x19, 0x86, 0x2f, 0x43, 0x59, 0xac,
+ 0x2a, 0xd3, 0x36, 0xe8, 0x53, 0xbe, 0x7b, 0xe6, 0x55, 0xb1, 0xd0, 0xda, 0x0c, 0x61, 0xdd, 0x3f,
+ 0xf4, 0x1d, 0x3b, 0x4a, 0x4d, 0xde, 0x05, 0x03, 0x78, 0xf7, 0x1f, 0xcc, 0x6f, 0xdc, 0xaf, 0x2d,
+ 0x1f, 0xde, 0x7c, 0x4e, 0xd5, 0xfe, 0x92, 0x81, 0x1c, 0xdf, 0x2f, 0xd6, 0xa0, 0x3c, 0xf8, 0xac,
+ 0xa7, 0x68, 0xad, 0xee, 0xf1, 0xfe, 0xa1, 0x82, 0x24, 0x5c, 0x05, 0xe0, 0xc0, 0xfd, 0xc3, 0x6e,
+ 0x63, 0x80, 0x32, 0x71, 0xbb, 0xdd, 0x19, 0xdc, 0xb9, 0x85, 0xb2, 0xb1, 0xc2, 0xb1, 0x00, 0x72,
+ 0x49, 0xc2, 0xfb, 0x37, 0x51, 0x1e, 0x23, 0xa8, 0x08, 0x03, 0xed, 0x4f, 0x95, 0xd6, 0x9d, 0x5b,
+ 0xa8, 0x90, 0x46, 0xde, 0xbf, 0x89, 0x56, 0xf0, 0x2a, 0x94, 0x38, 0xb2, 0xdf, 0xed, 0x1e, 0xa2,
+ 0x62, 0x6c, 0xb3, 0x3f, 0x50, 0xdb, 0x9d, 0x03, 0x54, 0x8a, 0x6d, 0x1e, 0xa8, 0xdd, 0xe3, 0x1e,
+ 0x82, 0xd8, 0xc2, 0x91, 0xd2, 0xef, 0x37, 0x0e, 0x14, 0x54, 0x8e, 0x19, 0xfb, 0x9f, 0x0d, 0x94,
+ 0x3e, 0xaa, 0xa4, 0xdc, 0x7a, 0xff, 0x26, 0x5a, 0x8d, 0xbb, 0x50, 0x3a, 0xc7, 0x47, 0xa8, 0x8a,
+ 0xd7, 0x61, 0x55, 0x74, 0x11, 0x39, 0xb1, 0x36, 0x07, 0xdd, 0xb9, 0x85, 0xd0, 0xcc, 0x11, 0x61,
+ 0x65, 0x3d, 0x05, 0xdc, 0xb9, 0x85, 0x70, 0xad, 0x09, 0x79, 0x9e, 0x5d, 0x18, 0x43, 0xf5, 0xb0,
+ 0xb1, 0xaf, 0x1c, 0x6a, 0xdd, 0xde, 0xa0, 0xdd, 0xed, 0x34, 0x0e, 0x91, 0x34, 0xc3, 0x54, 0xe5,
+ 0x67, 0xc7, 0x6d, 0x55, 0x69, 0xa1, 0x4c, 0x12, 0xeb, 0x29, 0x8d, 0x81, 0xd2, 0x42, 0xd9, 0x9a,
+ 0x0e, 0x9b, 0xcb, 0xf6, 0xc9, 0xa5, 0x2b, 0x23, 0x31, 0xc5, 0x99, 0x33, 0xa6, 0x98, 0xdb, 0x5a,
+ 0x98, 0xe2, 0x7f, 0x65, 0x60, 0x63, 0xc9, 0x59, 0xb1, 0xb4, 0x93, 0x1f, 0x43, 0x5e, 0xa4, 0xa8,
+ 0x38, 0x3d, 0xaf, 0x2d, 0x3d, 0x74, 0x78, 0xc2, 0x2e, 0x9c, 0xa0, 0x5c, 0x2f, 0x59, 0x41, 0x64,
+ 0xcf, 0xa8, 0x20, 0x98, 0x89, 0x85, 0x3d, 0xfd, 0x17, 0x0b, 0x7b, 0xba, 0x38, 0xf6, 0xee, 0x9c,
+ 0xe7, 0xd8, 0xe3, 0xd8, 0xb7, 0xdb, 0xdb, 0xf3, 0x4b, 0xf6, 0xf6, 0x7b, 0xb0, 0xbe, 0x60, 0xe8,
+ 0xdc, 0x7b, 0xec, 0xaf, 0x24, 0x90, 0xcf, 0x0a, 0xce, 0x73, 0x76, 0xba, 0x4c, 0x6a, 0xa7, 0xbb,
+ 0x37, 0x1f, 0xc1, 0x2b, 0x67, 0x4f, 0xc2, 0xc2, 0x5c, 0x7f, 0x25, 0xc1, 0x85, 0xe5, 0x95, 0xe2,
+ 0x52, 0x1f, 0x3e, 0x82, 0xc2, 0x84, 0x06, 0x63, 0x27, 0xaa, 0x96, 0xde, 0x5e, 0x72, 0x06, 0x33,
+ 0xf1, 0xfc, 0x64, 0x87, 0x5a, 0xc9, 0x43, 0x3c, 0x7b, 0x56, 0xb9, 0x27, 0xbc, 0x59, 0xf0, 0xf4,
+ 0xd7, 0x19, 0x78, 0x79, 0xa9, 0xf1, 0xa5, 0x8e, 0xbe, 0x06, 0x60, 0xda, 0xee, 0x34, 0x10, 0x15,
+ 0x91, 0xd8, 0x60, 0x4b, 0x1c, 0xe1, 0x9b, 0x17, 0xdb, 0x3c, 0xa7, 0x41, 0x2c, 0xcf, 0x72, 0x39,
+ 0x08, 0x88, 0x13, 0xee, 0xce, 0x1c, 0xcd, 0x71, 0x47, 0x5f, 0x3f, 0x63, 0xa4, 0x0b, 0x89, 0xf9,
+ 0x1e, 0x20, 0xdd, 0x32, 0xa9, 0x1d, 0x68, 0x7e, 0xe0, 0x51, 0x32, 0x31, 0xed, 0x11, 0x3f, 0x41,
+ 0x8a, 0x7b, 0xf9, 0x21, 0xb1, 0x7c, 0xaa, 0xae, 0x09, 0x71, 0x3f, 0x92, 0x32, 0x0d, 0x9e, 0x40,
+ 0x5e, 0x42, 0xa3, 0x90, 0xd2, 0x10, 0xe2, 0x58, 0xa3, 0xf6, 0xdb, 0x12, 0x94, 0x13, 0x75, 0x35,
+ 0xbe, 0x02, 0x95, 0x87, 0xe4, 0x31, 0xd1, 0xa2, 0xbb, 0x92, 0x88, 0x44, 0x99, 0x61, 0xbd, 0xf0,
+ 0xbe, 0xf4, 0x1e, 0x6c, 0x72, 0x8a, 0x33, 0x0d, 0xa8, 0xa7, 0xe9, 0x16, 0xf1, 0x7d, 0x1e, 0xb4,
+ 0x22, 0xa7, 0x62, 0x26, 0xeb, 0x32, 0x51, 0x33, 0x92, 0xe0, 0xdb, 0xb0, 0xc1, 0x35, 0x26, 0x53,
+ 0x2b, 0x30, 0x5d, 0x8b, 0x6a, 0xec, 0xf6, 0xe6, 0xf3, 0x93, 0x24, 0xf6, 0x6c, 0x9d, 0x31, 0x8e,
+ 0x42, 0x02, 0xf3, 0xc8, 0xc7, 0x2d, 0x78, 0x8d, 0xab, 0x8d, 0xa8, 0x4d, 0x3d, 0x12, 0x50, 0x8d,
+ 0x7e, 0x31, 0x25, 0x96, 0xaf, 0x11, 0xdb, 0xd0, 0xc6, 0xc4, 0x1f, 0xcb, 0x9b, 0xcc, 0xc0, 0x7e,
+ 0x46, 0x96, 0xd4, 0x4b, 0x8c, 0x78, 0x10, 0xf2, 0x14, 0x4e, 0x6b, 0xd8, 0xc6, 0xc7, 0xc4, 0x1f,
+ 0xe3, 0x3d, 0xb8, 0xc0, 0xad, 0xf8, 0x81, 0x67, 0xda, 0x23, 0x4d, 0x1f, 0x53, 0xfd, 0x91, 0x36,
+ 0x0d, 0x86, 0x77, 0xe5, 0x57, 0x92, 0xfd, 0x73, 0x0f, 0xfb, 0x9c, 0xd3, 0x64, 0x94, 0xe3, 0x60,
+ 0x78, 0x17, 0xf7, 0xa1, 0xc2, 0x26, 0x63, 0x62, 0x7e, 0x49, 0xb5, 0xa1, 0xe3, 0xf1, 0xa3, 0xb1,
+ 0xba, 0x64, 0x6b, 0x4a, 0x44, 0xb0, 0xde, 0x0d, 0x15, 0x8e, 0x1c, 0x83, 0xee, 0xe5, 0xfb, 0x3d,
+ 0x45, 0x69, 0xa9, 0xe5, 0xc8, 0xca, 0x7d, 0xc7, 0x63, 0x09, 0x35, 0x72, 0xe2, 0x00, 0x97, 0x45,
+ 0x42, 0x8d, 0x9c, 0x28, 0xbc, 0xb7, 0x61, 0x43, 0xd7, 0xc5, 0x98, 0x4d, 0x5d, 0x0b, 0xef, 0x58,
+ 0xbe, 0x8c, 0x52, 0xc1, 0xd2, 0xf5, 0x03, 0x41, 0x08, 0x73, 0xdc, 0xc7, 0x1f, 0xc2, 0xcb, 0xb3,
+ 0x60, 0x25, 0x15, 0xd7, 0x17, 0x46, 0x39, 0xaf, 0x7a, 0x1b, 0x36, 0xdc, 0xd3, 0x45, 0x45, 0x9c,
+ 0xea, 0xd1, 0x3d, 0x9d, 0x57, 0xfb, 0x00, 0x36, 0xdd, 0xb1, 0xbb, 0xa8, 0x77, 0x3d, 0xa9, 0x87,
+ 0xdd, 0xb1, 0x3b, 0xaf, 0xf8, 0x16, 0xbf, 0x70, 0x7b, 0x54, 0x27, 0x01, 0x35, 0xe4, 0x8b, 0x49,
+ 0x7a, 0x42, 0x80, 0x77, 0x01, 0xe9, 0xba, 0x46, 0x6d, 0x72, 0x62, 0x51, 0x8d, 0x78, 0xd4, 0x26,
+ 0xbe, 0x7c, 0x39, 0x49, 0xae, 0xea, 0xba, 0xc2, 0xa5, 0x0d, 0x2e, 0xc4, 0xd7, 0x61, 0xdd, 0x39,
+ 0x79, 0xa8, 0x8b, 0x94, 0xd4, 0x5c, 0x8f, 0x0e, 0xcd, 0xa7, 0xf2, 0x9b, 0x3c, 0xbe, 0x6b, 0x4c,
+ 0xc0, 0x13, 0xb2, 0xc7, 0x61, 0x7c, 0x0d, 0x90, 0xee, 0x8f, 0x89, 0xe7, 0xf2, 0x3d, 0xd9, 0x77,
+ 0x89, 0x4e, 0xe5, 0xb7, 0x04, 0x55, 0xe0, 0x9d, 0x08, 0x66, 0x4b, 0xc2, 0x7f, 0x62, 0x0e, 0x83,
+ 0xc8, 0xe2, 0x55, 0xb1, 0x24, 0x38, 0x16, 0x5a, 0xdb, 0x01, 0xc4, 0x42, 0x91, 0xea, 0x78, 0x87,
+ 0xd3, 0xaa, 0xee, 0xd8, 0x4d, 0xf6, 0xfb, 0x06, 0xac, 0x32, 0xe6, 0xac, 0xd3, 0x6b, 0xa2, 0x20,
+ 0x73, 0xc7, 0x89, 0x1e, 0x6f, 0xc1, 0x05, 0x46, 0x9a, 0xd0, 0x80, 0x18, 0x24, 0x20, 0x09, 0xf6,
+ 0xbb, 0x9c, 0xcd, 0xe2, 0x7e, 0x14, 0x0a, 0x53, 0x7e, 0x7a, 0xd3, 0x93, 0xd3, 0x38, 0xb3, 0x6e,
+ 0x08, 0x3f, 0x19, 0x16, 0xe5, 0xd6, 0xf7, 0x56, 0x74, 0xd7, 0xf6, 0xa0, 0x92, 0x4c, 0x7c, 0x5c,
+ 0x02, 0x91, 0xfa, 0x48, 0x62, 0x55, 0x50, 0xb3, 0xdb, 0x62, 0xf5, 0xcb, 0xe7, 0x0a, 0xca, 0xb0,
+ 0x3a, 0xea, 0xb0, 0x3d, 0x50, 0x34, 0xf5, 0xb8, 0x33, 0x68, 0x1f, 0x29, 0x28, 0x9b, 0x28, 0xd8,
+ 0x1f, 0xe4, 0x8a, 0x6f, 0xa3, 0xab, 0xb5, 0xaf, 0x33, 0x50, 0x4d, 0xdf, 0xc0, 0xf0, 0x8f, 0xe0,
+ 0x62, 0xf4, 0x5c, 0xe2, 0xd3, 0x40, 0x7b, 0x62, 0x7a, 0x7c, 0x45, 0x4e, 0x88, 0x38, 0x1d, 0xe3,
+ 0x9c, 0xd8, 0x0c, 0x59, 0x7d, 0x1a, 0x7c, 0x62, 0x7a, 0x6c, 0xbd, 0x4d, 0x48, 0x80, 0x0f, 0xe1,
+ 0xb2, 0xed, 0x68, 0x7e, 0x40, 0x6c, 0x83, 0x78, 0x86, 0x36, 0x7b, 0xa8, 0xd2, 0x88, 0xae, 0x53,
+ 0xdf, 0x77, 0xc4, 0x49, 0x18, 0x5b, 0x79, 0xd5, 0x76, 0xfa, 0x21, 0x79, 0x76, 0x44, 0x34, 0x42,
+ 0xea, 0x5c, 0xfe, 0x66, 0xcf, 0xca, 0xdf, 0x57, 0xa0, 0x34, 0x21, 0xae, 0x46, 0xed, 0xc0, 0x3b,
+ 0xe5, 0x75, 0x77, 0x51, 0x2d, 0x4e, 0x88, 0xab, 0xb0, 0xf6, 0x0b, 0xb9, 0xfe, 0x3c, 0xc8, 0x15,
+ 0x8b, 0xa8, 0xf4, 0x20, 0x57, 0x2c, 0x21, 0xa8, 0xfd, 0x33, 0x0b, 0x95, 0x64, 0x1d, 0xce, 0xae,
+ 0x35, 0x3a, 0x3f, 0xb2, 0x24, 0xbe, 0xa9, 0xbd, 0xf1, 0x8d, 0x55, 0x7b, 0xbd, 0xc9, 0xce, 0xb2,
+ 0xbd, 0x82, 0xa8, 0x8e, 0x55, 0xa1, 0xc9, 0xea, 0x08, 0x96, 0x6c, 0x54, 0x54, 0x23, 0x45, 0x35,
+ 0x6c, 0xe1, 0x03, 0x28, 0x3c, 0xf4, 0xb9, 0xed, 0x02, 0xb7, 0xfd, 0xe6, 0x37, 0xdb, 0x7e, 0xd0,
+ 0xe7, 0xc6, 0x4b, 0x0f, 0xfa, 0x5a, 0xa7, 0xab, 0x1e, 0x35, 0x0e, 0xd5, 0x50, 0x1d, 0x5f, 0x82,
+ 0x9c, 0x45, 0xbe, 0x3c, 0x4d, 0x9f, 0x7a, 0x1c, 0x3a, 0xef, 0x24, 0x5c, 0x82, 0xdc, 0x13, 0x4a,
+ 0x1e, 0xa5, 0xcf, 0x1a, 0x0e, 0x7d, 0x8f, 0x8b, 0x61, 0x17, 0xf2, 0x3c, 0x5e, 0x18, 0x20, 0x8c,
+ 0x18, 0x7a, 0x09, 0x17, 0x21, 0xd7, 0xec, 0xaa, 0x6c, 0x41, 0x20, 0xa8, 0x08, 0x54, 0xeb, 0xb5,
+ 0x95, 0xa6, 0x82, 0x32, 0xb5, 0xdb, 0x50, 0x10, 0x41, 0x60, 0x8b, 0x25, 0x0e, 0x03, 0x7a, 0x29,
+ 0x6c, 0x86, 0x36, 0xa4, 0x48, 0x7a, 0x7c, 0xb4, 0xaf, 0xa8, 0x28, 0x93, 0x9e, 0xea, 0x1c, 0xca,
+ 0xd7, 0x7c, 0xa8, 0x24, 0x0b, 0xf1, 0x17, 0x73, 0xc9, 0xfe, 0x9b, 0x04, 0xe5, 0x44, 0x61, 0xcd,
+ 0x2a, 0x22, 0x62, 0x59, 0xce, 0x13, 0x8d, 0x58, 0x26, 0xf1, 0xc3, 0xd4, 0x00, 0x0e, 0x35, 0x18,
+ 0x72, 0xde, 0xa9, 0x7b, 0x41, 0x4b, 0x24, 0x8f, 0x0a, 0xb5, 0x3f, 0x4a, 0x80, 0xe6, 0x2b, 0xdb,
+ 0x39, 0x37, 0xa5, 0x1f, 0xd2, 0xcd, 0xda, 0x1f, 0x24, 0xa8, 0xa6, 0xcb, 0xd9, 0x39, 0xf7, 0xae,
+ 0xfc, 0xa0, 0xee, 0xfd, 0x23, 0x03, 0xab, 0xa9, 0x22, 0xf6, 0xbc, 0xde, 0x7d, 0x01, 0xeb, 0xa6,
+ 0x41, 0x27, 0xae, 0x13, 0x50, 0x5b, 0x3f, 0xd5, 0x2c, 0xfa, 0x98, 0x5a, 0x72, 0x8d, 0x6f, 0x1a,
+ 0xbb, 0xdf, 0x5c, 0x26, 0xd7, 0xdb, 0x33, 0xbd, 0x43, 0xa6, 0xb6, 0xb7, 0xd1, 0x6e, 0x29, 0x47,
+ 0xbd, 0xee, 0x40, 0xe9, 0x34, 0x3f, 0xd3, 0x8e, 0x3b, 0x3f, 0xed, 0x74, 0x3f, 0xe9, 0xa8, 0xc8,
+ 0x9c, 0xa3, 0x7d, 0x8f, 0xcb, 0xbe, 0x07, 0x68, 0xde, 0x29, 0x7c, 0x11, 0x96, 0xb9, 0x85, 0x5e,
+ 0xc2, 0x1b, 0xb0, 0xd6, 0xe9, 0x6a, 0xfd, 0x76, 0x4b, 0xd1, 0x94, 0xfb, 0xf7, 0x95, 0xe6, 0xa0,
+ 0x2f, 0x1e, 0x3e, 0x62, 0xf6, 0x20, 0xb5, 0xc0, 0x6b, 0xbf, 0xcf, 0xc2, 0xc6, 0x12, 0x4f, 0x70,
+ 0x23, 0xbc, 0xb2, 0x88, 0x5b, 0xd4, 0x8d, 0xf3, 0x78, 0x5f, 0x67, 0x35, 0x43, 0x8f, 0x78, 0x41,
+ 0x78, 0xc3, 0xb9, 0x06, 0x2c, 0x4a, 0x76, 0x60, 0x0e, 0x4d, 0xea, 0x85, 0xef, 0x44, 0xe2, 0x1e,
+ 0xb3, 0x36, 0xc3, 0xc5, 0x53, 0xd1, 0xbb, 0x80, 0x5d, 0xc7, 0x37, 0x03, 0xf3, 0x31, 0xd5, 0x4c,
+ 0x3b, 0x7a, 0x54, 0x62, 0xf7, 0x9a, 0x9c, 0x8a, 0x22, 0x49, 0xdb, 0x0e, 0x62, 0xb6, 0x4d, 0x47,
+ 0x64, 0x8e, 0xcd, 0x36, 0xf3, 0xac, 0x8a, 0x22, 0x49, 0xcc, 0xbe, 0x02, 0x15, 0xc3, 0x99, 0xb2,
+ 0x62, 0x4f, 0xf0, 0xd8, 0xd9, 0x21, 0xa9, 0x65, 0x81, 0xc5, 0x94, 0xb0, 0x8c, 0x9f, 0xbd, 0x66,
+ 0x55, 0xd4, 0xb2, 0xc0, 0x04, 0xe5, 0x2a, 0xac, 0x91, 0xd1, 0xc8, 0x63, 0xc6, 0x23, 0x43, 0xe2,
+ 0x62, 0x52, 0x8d, 0x61, 0x4e, 0xdc, 0x7a, 0x00, 0xc5, 0x28, 0x0e, 0xec, 0xa8, 0x66, 0x91, 0xd0,
+ 0x5c, 0x71, 0xdb, 0xce, 0xec, 0x94, 0xd4, 0xa2, 0x1d, 0x09, 0xaf, 0x40, 0xc5, 0xf4, 0xb5, 0xd9,
+ 0xe3, 0x7c, 0x66, 0x3b, 0xb3, 0x53, 0x54, 0xcb, 0xa6, 0x1f, 0x3f, 0x6c, 0xd6, 0xbe, 0xca, 0x40,
+ 0x35, 0xfd, 0x71, 0x01, 0xb7, 0xa0, 0x68, 0x39, 0x3a, 0xe1, 0xa9, 0x25, 0xbe, 0x6c, 0xed, 0x3c,
+ 0xe7, 0x7b, 0x44, 0xfd, 0x30, 0xe4, 0xab, 0xb1, 0xe6, 0xd6, 0xdf, 0x25, 0x28, 0x46, 0x30, 0xbe,
+ 0x00, 0x39, 0x97, 0x04, 0x63, 0x6e, 0x2e, 0xbf, 0x9f, 0x41, 0x92, 0xca, 0xdb, 0x0c, 0xf7, 0x5d,
+ 0x62, 0xf3, 0x14, 0x08, 0x71, 0xd6, 0x66, 0xf3, 0x6a, 0x51, 0x62, 0xf0, 0x5b, 0x8f, 0x33, 0x99,
+ 0x50, 0x3b, 0xf0, 0xa3, 0x79, 0x0d, 0xf1, 0x66, 0x08, 0xe3, 0x77, 0x60, 0x3d, 0xf0, 0x88, 0x69,
+ 0xa5, 0xb8, 0x39, 0xce, 0x45, 0x91, 0x20, 0x26, 0xef, 0xc1, 0xa5, 0xc8, 0xae, 0x41, 0x03, 0xa2,
+ 0x8f, 0xa9, 0x31, 0x53, 0x2a, 0xf0, 0xd7, 0x8d, 0x8b, 0x21, 0xa1, 0x15, 0xca, 0x23, 0xdd, 0xda,
+ 0xd7, 0x12, 0xac, 0x47, 0xf7, 0x34, 0x23, 0x0e, 0xd6, 0x11, 0x00, 0xb1, 0x6d, 0x27, 0x48, 0x86,
+ 0x6b, 0x31, 0x95, 0x17, 0xf4, 0xea, 0x8d, 0x58, 0x49, 0x4d, 0x18, 0xd8, 0x9a, 0x00, 0xcc, 0x24,
+ 0x67, 0x86, 0xed, 0x32, 0x94, 0xc3, 0x2f, 0x47, 0xfc, 0xf3, 0xa3, 0xb8, 0xd9, 0x83, 0x80, 0xd8,
+ 0x85, 0x0e, 0x6f, 0x42, 0xfe, 0x84, 0x8e, 0x4c, 0x3b, 0x7c, 0x0f, 0x16, 0x8d, 0xe8, 0xfd, 0x25,
+ 0x17, 0xbf, 0xbf, 0xec, 0xff, 0x46, 0x82, 0x0d, 0xdd, 0x99, 0xcc, 0xfb, 0xbb, 0x8f, 0xe6, 0x9e,
+ 0x17, 0xfc, 0x8f, 0xa5, 0xcf, 0x3f, 0x1a, 0x99, 0xc1, 0x78, 0x7a, 0x52, 0xd7, 0x9d, 0xc9, 0xee,
+ 0xc8, 0xb1, 0x88, 0x3d, 0x9a, 0x7d, 0x3f, 0xe5, 0x7f, 0xf4, 0x1b, 0x23, 0x6a, 0xdf, 0x18, 0x39,
+ 0x89, 0xaf, 0xa9, 0xf7, 0x66, 0x7f, 0xff, 0x27, 0x49, 0x7f, 0xca, 0x64, 0x0f, 0x7a, 0xfb, 0x7f,
+ 0xce, 0x6c, 0x1d, 0x88, 0xee, 0x7a, 0x51, 0x78, 0x54, 0x3a, 0xb4, 0xa8, 0xce, 0x86, 0xfc, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0x3e, 0xe8, 0xef, 0xc4, 0x9b, 0x1d, 0x00, 0x00,
}
diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto
new file mode 100644
index 000000000..ed08fcbc5
--- /dev/null
+++ b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto
@@ -0,0 +1,883 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+//
+// The messages in this file describe the definitions found in .proto files.
+// A valid .proto file can be translated directly to a FileDescriptorProto
+// without any other information (e.g. without reading its imports).
+
+
+syntax = "proto2";
+
+package google.protobuf;
+option go_package = "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DescriptorProtos";
+option csharp_namespace = "Google.Protobuf.Reflection";
+option objc_class_prefix = "GPB";
+option cc_enable_arenas = true;
+
+// descriptor.proto must be optimized for speed because reflection-based
+// algorithms don't work during bootstrapping.
+option optimize_for = SPEED;
+
+// The protocol compiler can output a FileDescriptorSet containing the .proto
+// files it parses.
+message FileDescriptorSet {
+ repeated FileDescriptorProto file = 1;
+}
+
+// Describes a complete .proto file.
+message FileDescriptorProto {
+ optional string name = 1; // file name, relative to root of source tree
+ optional string package = 2; // e.g. "foo", "foo.bar", etc.
+
+ // Names of files imported by this file.
+ repeated string dependency = 3;
+ // Indexes of the public imported files in the dependency list above.
+ repeated int32 public_dependency = 10;
+ // Indexes of the weak imported files in the dependency list.
+ // For Google-internal migration only. Do not use.
+ repeated int32 weak_dependency = 11;
+
+ // All top-level definitions in this file.
+ repeated DescriptorProto message_type = 4;
+ repeated EnumDescriptorProto enum_type = 5;
+ repeated ServiceDescriptorProto service = 6;
+ repeated FieldDescriptorProto extension = 7;
+
+ optional FileOptions options = 8;
+
+ // This field contains optional information about the original source code.
+ // You may safely remove this entire field without harming runtime
+ // functionality of the descriptors -- the information is needed only by
+ // development tools.
+ optional SourceCodeInfo source_code_info = 9;
+
+ // The syntax of the proto file.
+ // The supported values are "proto2" and "proto3".
+ optional string syntax = 12;
+}
+
+// Describes a message type.
+message DescriptorProto {
+ optional string name = 1;
+
+ repeated FieldDescriptorProto field = 2;
+ repeated FieldDescriptorProto extension = 6;
+
+ repeated DescriptorProto nested_type = 3;
+ repeated EnumDescriptorProto enum_type = 4;
+
+ message ExtensionRange {
+ optional int32 start = 1;
+ optional int32 end = 2;
+
+ optional ExtensionRangeOptions options = 3;
+ }
+ repeated ExtensionRange extension_range = 5;
+
+ repeated OneofDescriptorProto oneof_decl = 8;
+
+ optional MessageOptions options = 7;
+
+ // Range of reserved tag numbers. Reserved tag numbers may not be used by
+ // fields or extension ranges in the same message. Reserved ranges may
+ // not overlap.
+ message ReservedRange {
+ optional int32 start = 1; // Inclusive.
+ optional int32 end = 2; // Exclusive.
+ }
+ repeated ReservedRange reserved_range = 9;
+ // Reserved field names, which may not be used by fields in the same message.
+ // A given name may only be reserved once.
+ repeated string reserved_name = 10;
+}
+
+message ExtensionRangeOptions {
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+// Describes a field within a message.
+message FieldDescriptorProto {
+ enum Type {
+ // 0 is reserved for errors.
+ // Order is weird for historical reasons.
+ TYPE_DOUBLE = 1;
+ TYPE_FLOAT = 2;
+ // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
+ // negative values are likely.
+ TYPE_INT64 = 3;
+ TYPE_UINT64 = 4;
+ // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
+ // negative values are likely.
+ TYPE_INT32 = 5;
+ TYPE_FIXED64 = 6;
+ TYPE_FIXED32 = 7;
+ TYPE_BOOL = 8;
+ TYPE_STRING = 9;
+ // Tag-delimited aggregate.
+ // Group type is deprecated and not supported in proto3. However, Proto3
+ // implementations should still be able to parse the group wire format and
+ // treat group fields as unknown fields.
+ TYPE_GROUP = 10;
+ TYPE_MESSAGE = 11; // Length-delimited aggregate.
+
+ // New in version 2.
+ TYPE_BYTES = 12;
+ TYPE_UINT32 = 13;
+ TYPE_ENUM = 14;
+ TYPE_SFIXED32 = 15;
+ TYPE_SFIXED64 = 16;
+ TYPE_SINT32 = 17; // Uses ZigZag encoding.
+ TYPE_SINT64 = 18; // Uses ZigZag encoding.
+ };
+
+ enum Label {
+ // 0 is reserved for errors
+ LABEL_OPTIONAL = 1;
+ LABEL_REQUIRED = 2;
+ LABEL_REPEATED = 3;
+ };
+
+ optional string name = 1;
+ optional int32 number = 3;
+ optional Label label = 4;
+
+ // If type_name is set, this need not be set. If both this and type_name
+ // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
+ optional Type type = 5;
+
+ // For message and enum types, this is the name of the type. If the name
+ // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
+ // rules are used to find the type (i.e. first the nested types within this
+ // message are searched, then within the parent, on up to the root
+ // namespace).
+ optional string type_name = 6;
+
+ // For extensions, this is the name of the type being extended. It is
+ // resolved in the same manner as type_name.
+ optional string extendee = 2;
+
+ // For numeric types, contains the original text representation of the value.
+ // For booleans, "true" or "false".
+ // For strings, contains the default text contents (not escaped in any way).
+ // For bytes, contains the C escaped value. All bytes >= 128 are escaped.
+ // TODO(kenton): Base-64 encode?
+ optional string default_value = 7;
+
+ // If set, gives the index of a oneof in the containing type's oneof_decl
+ // list. This field is a member of that oneof.
+ optional int32 oneof_index = 9;
+
+ // JSON name of this field. The value is set by protocol compiler. If the
+ // user has set a "json_name" option on this field, that option's value
+ // will be used. Otherwise, it's deduced from the field's name by converting
+ // it to camelCase.
+ optional string json_name = 10;
+
+ optional FieldOptions options = 8;
+}
+
+// Describes a oneof.
+message OneofDescriptorProto {
+ optional string name = 1;
+ optional OneofOptions options = 2;
+}
+
+// Describes an enum type.
+message EnumDescriptorProto {
+ optional string name = 1;
+
+ repeated EnumValueDescriptorProto value = 2;
+
+ optional EnumOptions options = 3;
+
+ // Range of reserved numeric values. Reserved values may not be used by
+ // entries in the same enum. Reserved ranges may not overlap.
+ //
+ // Note that this is distinct from DescriptorProto.ReservedRange in that it
+ // is inclusive such that it can appropriately represent the entire int32
+ // domain.
+ message EnumReservedRange {
+ optional int32 start = 1; // Inclusive.
+ optional int32 end = 2; // Inclusive.
+ }
+
+ // Range of reserved numeric values. Reserved numeric values may not be used
+ // by enum values in the same enum declaration. Reserved ranges may not
+ // overlap.
+ repeated EnumReservedRange reserved_range = 4;
+
+ // Reserved enum value names, which may not be reused. A given name may only
+ // be reserved once.
+ repeated string reserved_name = 5;
+}
+
+// Describes a value within an enum.
+message EnumValueDescriptorProto {
+ optional string name = 1;
+ optional int32 number = 2;
+
+ optional EnumValueOptions options = 3;
+}
+
+// Describes a service.
+message ServiceDescriptorProto {
+ optional string name = 1;
+ repeated MethodDescriptorProto method = 2;
+
+ optional ServiceOptions options = 3;
+}
+
+// Describes a method of a service.
+message MethodDescriptorProto {
+ optional string name = 1;
+
+ // Input and output type names. These are resolved in the same way as
+ // FieldDescriptorProto.type_name, but must refer to a message type.
+ optional string input_type = 2;
+ optional string output_type = 3;
+
+ optional MethodOptions options = 4;
+
+ // Identifies if client streams multiple client messages
+ optional bool client_streaming = 5 [default=false];
+ // Identifies if server streams multiple server messages
+ optional bool server_streaming = 6 [default=false];
+}
+
+
+// ===================================================================
+// Options
+
+// Each of the definitions above may have "options" attached. These are
+// just annotations which may cause code to be generated slightly differently
+// or may contain hints for code that manipulates protocol messages.
+//
+// Clients may define custom options as extensions of the *Options messages.
+// These extensions may not yet be known at parsing time, so the parser cannot
+// store the values in them. Instead it stores them in a field in the *Options
+// message called uninterpreted_option. This field must have the same name
+// across all *Options messages. We then use this field to populate the
+// extensions when we build a descriptor, at which point all protos have been
+// parsed and so all extensions are known.
+//
+// Extension numbers for custom options may be chosen as follows:
+// * For options which will only be used within a single application or
+// organization, or for experimental options, use field numbers 50000
+// through 99999. It is up to you to ensure that you do not use the
+// same number for multiple options.
+// * For options which will be published and used publicly by multiple
+// independent entities, e-mail protobuf-global-extension-registry@google.com
+// to reserve extension numbers. Simply provide your project name (e.g.
+// Objective-C plugin) and your project website (if available) -- there's no
+// need to explain how you intend to use them. Usually you only need one
+// extension number. You can declare multiple options with only one extension
+// number by putting them in a sub-message. See the Custom Options section of
+// the docs for examples:
+// https://developers.google.com/protocol-buffers/docs/proto#options
+// If this turns out to be popular, a web service will be set up
+// to automatically assign option numbers.
+
+
+message FileOptions {
+
+ // Sets the Java package where classes generated from this .proto will be
+ // placed. By default, the proto package is used, but this is often
+ // inappropriate because proto packages do not normally start with backwards
+ // domain names.
+ optional string java_package = 1;
+
+
+ // If set, all the classes from the .proto file are wrapped in a single
+ // outer class with the given name. This applies to both Proto1
+ // (equivalent to the old "--one_java_file" option) and Proto2 (where
+ // a .proto always translates to a single class, but you may want to
+ // explicitly choose the class name).
+ optional string java_outer_classname = 8;
+
+ // If set true, then the Java code generator will generate a separate .java
+ // file for each top-level message, enum, and service defined in the .proto
+ // file. Thus, these types will *not* be nested inside the outer class
+ // named by java_outer_classname. However, the outer class will still be
+ // generated to contain the file's getDescriptor() method as well as any
+ // top-level extensions defined in the file.
+ optional bool java_multiple_files = 10 [default=false];
+
+ // This option does nothing.
+ optional bool java_generate_equals_and_hash = 20 [deprecated=true];
+
+ // If set true, then the Java2 code generator will generate code that
+ // throws an exception whenever an attempt is made to assign a non-UTF-8
+ // byte sequence to a string field.
+ // Message reflection will do the same.
+ // However, an extension field still accepts non-UTF-8 byte sequences.
+ // This option has no effect on when used with the lite runtime.
+ optional bool java_string_check_utf8 = 27 [default=false];
+
+
+ // Generated classes can be optimized for speed or code size.
+ enum OptimizeMode {
+ SPEED = 1; // Generate complete code for parsing, serialization,
+ // etc.
+ CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
+ LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
+ }
+ optional OptimizeMode optimize_for = 9 [default=SPEED];
+
+ // Sets the Go package where structs generated from this .proto will be
+ // placed. If omitted, the Go package will be derived from the following:
+ // - The basename of the package import path, if provided.
+ // - Otherwise, the package statement in the .proto file, if present.
+ // - Otherwise, the basename of the .proto file, without extension.
+ optional string go_package = 11;
+
+
+
+ // Should generic services be generated in each language? "Generic" services
+ // are not specific to any particular RPC system. They are generated by the
+ // main code generators in each language (without additional plugins).
+ // Generic services were the only kind of service generation supported by
+ // early versions of google.protobuf.
+ //
+ // Generic services are now considered deprecated in favor of using plugins
+ // that generate code specific to your particular RPC system. Therefore,
+ // these default to false. Old code which depends on generic services should
+ // explicitly set them to true.
+ optional bool cc_generic_services = 16 [default=false];
+ optional bool java_generic_services = 17 [default=false];
+ optional bool py_generic_services = 18 [default=false];
+ optional bool php_generic_services = 42 [default=false];
+
+ // Is this file deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for everything in the file, or it will be completely ignored; in the very
+ // least, this is a formalization for deprecating files.
+ optional bool deprecated = 23 [default=false];
+
+ // Enables the use of arenas for the proto messages in this file. This applies
+ // only to generated classes for C++.
+ optional bool cc_enable_arenas = 31 [default=false];
+
+
+ // Sets the objective c class prefix which is prepended to all objective c
+ // generated classes from this .proto. There is no default.
+ optional string objc_class_prefix = 36;
+
+ // Namespace for generated classes; defaults to the package.
+ optional string csharp_namespace = 37;
+
+ // By default Swift generators will take the proto package and CamelCase it
+ // replacing '.' with underscore and use that to prefix the types/symbols
+ // defined. When this options is provided, they will use this value instead
+ // to prefix the types/symbols defined.
+ optional string swift_prefix = 39;
+
+ // Sets the php class prefix which is prepended to all php generated classes
+ // from this .proto. Default is empty.
+ optional string php_class_prefix = 40;
+
+ // Use this option to change the namespace of php generated classes. Default
+ // is empty. When this option is empty, the package name will be used for
+ // determining the namespace.
+ optional string php_namespace = 41;
+
+
+ // Use this option to change the namespace of php generated metadata classes.
+ // Default is empty. When this option is empty, the proto file name will be used
+ // for determining the namespace.
+ optional string php_metadata_namespace = 44;
+
+ // Use this option to change the package of ruby generated classes. Default
+ // is empty. When this option is not set, the package name will be used for
+ // determining the ruby package.
+ optional string ruby_package = 45;
+
+ // The parser stores options it doesn't recognize here.
+ // See the documentation for the "Options" section above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message.
+ // See the documentation for the "Options" section above.
+ extensions 1000 to max;
+
+ reserved 38;
+}
+
+message MessageOptions {
+ // Set true to use the old proto1 MessageSet wire format for extensions.
+ // This is provided for backwards-compatibility with the MessageSet wire
+ // format. You should not use this for any other reason: It's less
+ // efficient, has fewer features, and is more complicated.
+ //
+ // The message must be defined exactly as follows:
+ // message Foo {
+ // option message_set_wire_format = true;
+ // extensions 4 to max;
+ // }
+ // Note that the message cannot have any defined fields; MessageSets only
+ // have extensions.
+ //
+ // All extensions of your type must be singular messages; e.g. they cannot
+ // be int32s, enums, or repeated messages.
+ //
+ // Because this is an option, the above two restrictions are not enforced by
+ // the protocol compiler.
+ optional bool message_set_wire_format = 1 [default=false];
+
+ // Disables the generation of the standard "descriptor()" accessor, which can
+ // conflict with a field of the same name. This is meant to make migration
+ // from proto1 easier; new code should avoid fields named "descriptor".
+ optional bool no_standard_descriptor_accessor = 2 [default=false];
+
+ // Is this message deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the message, or it will be completely ignored; in the very least,
+ // this is a formalization for deprecating messages.
+ optional bool deprecated = 3 [default=false];
+
+ // Whether the message is an automatically generated map entry type for the
+ // maps field.
+ //
+ // For maps fields:
+ // map<KeyType, ValueType> map_field = 1;
+ // The parsed descriptor looks like:
+ // message MapFieldEntry {
+ // option map_entry = true;
+ // optional KeyType key = 1;
+ // optional ValueType value = 2;
+ // }
+ // repeated MapFieldEntry map_field = 1;
+ //
+ // Implementations may choose not to generate the map_entry=true message, but
+ // use a native map in the target language to hold the keys and values.
+ // The reflection APIs in such implementions still need to work as
+ // if the field is a repeated message field.
+ //
+ // NOTE: Do not set the option in .proto files. Always use the maps syntax
+ // instead. The option should only be implicitly set by the proto compiler
+ // parser.
+ optional bool map_entry = 7;
+
+ reserved 8; // javalite_serializable
+ reserved 9; // javanano_as_lite
+
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+message FieldOptions {
+ // The ctype option instructs the C++ code generator to use a different
+ // representation of the field than it normally would. See the specific
+ // options below. This option is not yet implemented in the open source
+ // release -- sorry, we'll try to include it in a future version!
+ optional CType ctype = 1 [default = STRING];
+ enum CType {
+ // Default mode.
+ STRING = 0;
+
+ CORD = 1;
+
+ STRING_PIECE = 2;
+ }
+ // The packed option can be enabled for repeated primitive fields to enable
+ // a more efficient representation on the wire. Rather than repeatedly
+ // writing the tag and type for each element, the entire array is encoded as
+ // a single length-delimited blob. In proto3, only explicit setting it to
+ // false will avoid using packed encoding.
+ optional bool packed = 2;
+
+ // The jstype option determines the JavaScript type used for values of the
+ // field. The option is permitted only for 64 bit integral and fixed types
+ // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING
+ // is represented as JavaScript string, which avoids loss of precision that
+ // can happen when a large value is converted to a floating point JavaScript.
+ // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
+ // use the JavaScript "number" type. The behavior of the default option
+ // JS_NORMAL is implementation dependent.
+ //
+ // This option is an enum to permit additional types to be added, e.g.
+ // goog.math.Integer.
+ optional JSType jstype = 6 [default = JS_NORMAL];
+ enum JSType {
+ // Use the default type.
+ JS_NORMAL = 0;
+
+ // Use JavaScript strings.
+ JS_STRING = 1;
+
+ // Use JavaScript numbers.
+ JS_NUMBER = 2;
+ }
+
+ // Should this field be parsed lazily? Lazy applies only to message-type
+ // fields. It means that when the outer message is initially parsed, the
+ // inner message's contents will not be parsed but instead stored in encoded
+ // form. The inner message will actually be parsed when it is first accessed.
+ //
+ // This is only a hint. Implementations are free to choose whether to use
+ // eager or lazy parsing regardless of the value of this option. However,
+ // setting this option true suggests that the protocol author believes that
+ // using lazy parsing on this field is worth the additional bookkeeping
+ // overhead typically needed to implement it.
+ //
+ // This option does not affect the public interface of any generated code;
+ // all method signatures remain the same. Furthermore, thread-safety of the
+ // interface is not affected by this option; const methods remain safe to
+ // call from multiple threads concurrently, while non-const methods continue
+ // to require exclusive access.
+ //
+ //
+ // Note that implementations may choose not to check required fields within
+ // a lazy sub-message. That is, calling IsInitialized() on the outer message
+ // may return true even if the inner message has missing required fields.
+ // This is necessary because otherwise the inner message would have to be
+ // parsed in order to perform the check, defeating the purpose of lazy
+ // parsing. An implementation which chooses not to check required fields
+ // must be consistent about it. That is, for any particular sub-message, the
+ // implementation must either *always* check its required fields, or *never*
+ // check its required fields, regardless of whether or not the message has
+ // been parsed.
+ optional bool lazy = 5 [default=false];
+
+ // Is this field deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for accessors, or it will be completely ignored; in the very least, this
+ // is a formalization for deprecating fields.
+ optional bool deprecated = 3 [default=false];
+
+ // For Google-internal migration only. Do not use.
+ optional bool weak = 10 [default=false];
+
+
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+
+ reserved 4; // removed jtype
+}
+
+message OneofOptions {
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+message EnumOptions {
+
+ // Set this option to true to allow mapping different tag names to the same
+ // value.
+ optional bool allow_alias = 2;
+
+ // Is this enum deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the enum, or it will be completely ignored; in the very least, this
+ // is a formalization for deprecating enums.
+ optional bool deprecated = 3 [default=false];
+
+ reserved 5; // javanano_as_lite
+
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+message EnumValueOptions {
+ // Is this enum value deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the enum value, or it will be completely ignored; in the very least,
+ // this is a formalization for deprecating enum values.
+ optional bool deprecated = 1 [default=false];
+
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+message ServiceOptions {
+
+ // Note: Field numbers 1 through 32 are reserved for Google's internal RPC
+ // framework. We apologize for hoarding these numbers to ourselves, but
+ // we were already using them long before we decided to release Protocol
+ // Buffers.
+
+ // Is this service deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the service, or it will be completely ignored; in the very least,
+ // this is a formalization for deprecating services.
+ optional bool deprecated = 33 [default=false];
+
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+message MethodOptions {
+
+ // Note: Field numbers 1 through 32 are reserved for Google's internal RPC
+ // framework. We apologize for hoarding these numbers to ourselves, but
+ // we were already using them long before we decided to release Protocol
+ // Buffers.
+
+ // Is this method deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the method, or it will be completely ignored; in the very least,
+ // this is a formalization for deprecating methods.
+ optional bool deprecated = 33 [default=false];
+
+ // Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
+ // or neither? HTTP based RPC implementation may choose GET verb for safe
+ // methods, and PUT verb for idempotent methods instead of the default POST.
+ enum IdempotencyLevel {
+ IDEMPOTENCY_UNKNOWN = 0;
+ NO_SIDE_EFFECTS = 1; // implies idempotent
+ IDEMPOTENT = 2; // idempotent, but may have side effects
+ }
+ optional IdempotencyLevel idempotency_level =
+ 34 [default=IDEMPOTENCY_UNKNOWN];
+
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+
+// A message representing a option the parser does not recognize. This only
+// appears in options protos created by the compiler::Parser class.
+// DescriptorPool resolves these when building Descriptor objects. Therefore,
+// options protos in descriptor objects (e.g. returned by Descriptor::options(),
+// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
+// in them.
+message UninterpretedOption {
+ // The name of the uninterpreted option. Each string represents a segment in
+ // a dot-separated name. is_extension is true iff a segment represents an
+ // extension (denoted with parentheses in options specs in .proto files).
+ // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
+ // "foo.(bar.baz).qux".
+ message NamePart {
+ required string name_part = 1;
+ required bool is_extension = 2;
+ }
+ repeated NamePart name = 2;
+
+ // The value of the uninterpreted option, in whatever type the tokenizer
+ // identified it as during parsing. Exactly one of these should be set.
+ optional string identifier_value = 3;
+ optional uint64 positive_int_value = 4;
+ optional int64 negative_int_value = 5;
+ optional double double_value = 6;
+ optional bytes string_value = 7;
+ optional string aggregate_value = 8;
+}
+
+// ===================================================================
+// Optional source code info
+
+// Encapsulates information about the original source file from which a
+// FileDescriptorProto was generated.
+message SourceCodeInfo {
+ // A Location identifies a piece of source code in a .proto file which
+ // corresponds to a particular definition. This information is intended
+ // to be useful to IDEs, code indexers, documentation generators, and similar
+ // tools.
+ //
+ // For example, say we have a file like:
+ // message Foo {
+ // optional string foo = 1;
+ // }
+ // Let's look at just the field definition:
+ // optional string foo = 1;
+ // ^ ^^ ^^ ^ ^^^
+ // a bc de f ghi
+ // We have the following locations:
+ // span path represents
+ // [a,i) [ 4, 0, 2, 0 ] The whole field definition.
+ // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional).
+ // [c,d) [ 4, 0, 2, 0, 5 ] The type (string).
+ // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo).
+ // [g,h) [ 4, 0, 2, 0, 3 ] The number (1).
+ //
+ // Notes:
+ // - A location may refer to a repeated field itself (i.e. not to any
+ // particular index within it). This is used whenever a set of elements are
+ // logically enclosed in a single code segment. For example, an entire
+ // extend block (possibly containing multiple extension definitions) will
+ // have an outer location whose path refers to the "extensions" repeated
+ // field without an index.
+ // - Multiple locations may have the same path. This happens when a single
+ // logical declaration is spread out across multiple places. The most
+ // obvious example is the "extend" block again -- there may be multiple
+ // extend blocks in the same scope, each of which will have the same path.
+ // - A location's span is not always a subset of its parent's span. For
+ // example, the "extendee" of an extension declaration appears at the
+ // beginning of the "extend" block and is shared by all extensions within
+ // the block.
+ // - Just because a location's span is a subset of some other location's span
+ // does not mean that it is a descendent. For example, a "group" defines
+ // both a type and a field in a single declaration. Thus, the locations
+ // corresponding to the type and field and their components will overlap.
+ // - Code which tries to interpret locations should probably be designed to
+ // ignore those that it doesn't understand, as more types of locations could
+ // be recorded in the future.
+ repeated Location location = 1;
+ message Location {
+ // Identifies which part of the FileDescriptorProto was defined at this
+ // location.
+ //
+ // Each element is a field number or an index. They form a path from
+ // the root FileDescriptorProto to the place where the definition. For
+ // example, this path:
+ // [ 4, 3, 2, 7, 1 ]
+ // refers to:
+ // file.message_type(3) // 4, 3
+ // .field(7) // 2, 7
+ // .name() // 1
+ // This is because FileDescriptorProto.message_type has field number 4:
+ // repeated DescriptorProto message_type = 4;
+ // and DescriptorProto.field has field number 2:
+ // repeated FieldDescriptorProto field = 2;
+ // and FieldDescriptorProto.name has field number 1:
+ // optional string name = 1;
+ //
+ // Thus, the above path gives the location of a field name. If we removed
+ // the last element:
+ // [ 4, 3, 2, 7 ]
+ // this path refers to the whole field declaration (from the beginning
+ // of the label to the terminating semicolon).
+ repeated int32 path = 1 [packed=true];
+
+ // Always has exactly three or four elements: start line, start column,
+ // end line (optional, otherwise assumed same as start line), end column.
+ // These are packed into a single field for efficiency. Note that line
+ // and column numbers are zero-based -- typically you will want to add
+ // 1 to each before displaying to a user.
+ repeated int32 span = 2 [packed=true];
+
+ // If this SourceCodeInfo represents a complete declaration, these are any
+ // comments appearing before and after the declaration which appear to be
+ // attached to the declaration.
+ //
+ // A series of line comments appearing on consecutive lines, with no other
+ // tokens appearing on those lines, will be treated as a single comment.
+ //
+ // leading_detached_comments will keep paragraphs of comments that appear
+ // before (but not connected to) the current element. Each paragraph,
+ // separated by empty lines, will be one comment element in the repeated
+ // field.
+ //
+ // Only the comment content is provided; comment markers (e.g. //) are
+ // stripped out. For block comments, leading whitespace and an asterisk
+ // will be stripped from the beginning of each line other than the first.
+ // Newlines are included in the output.
+ //
+ // Examples:
+ //
+ // optional int32 foo = 1; // Comment attached to foo.
+ // // Comment attached to bar.
+ // optional int32 bar = 2;
+ //
+ // optional string baz = 3;
+ // // Comment attached to baz.
+ // // Another line attached to baz.
+ //
+ // // Comment attached to qux.
+ // //
+ // // Another line attached to qux.
+ // optional double qux = 4;
+ //
+ // // Detached comment for corge. This is not leading or trailing comments
+ // // to qux or corge because there are blank lines separating it from
+ // // both.
+ //
+ // // Detached comment for corge paragraph 2.
+ //
+ // optional string corge = 5;
+ // /* Block comment attached
+ // * to corge. Leading asterisks
+ // * will be removed. */
+ // /* Block comment attached to
+ // * grault. */
+ // optional int32 grault = 6;
+ //
+ // // ignored detached comments.
+ optional string leading_comments = 3;
+ optional string trailing_comments = 4;
+ repeated string leading_detached_comments = 6;
+ }
+}
+
+// Describes the relationship between generated code and its original source
+// file. A GeneratedCodeInfo message is associated with only one generated
+// source file, but may contain references to different source .proto files.
+message GeneratedCodeInfo {
+ // An Annotation connects some span of text in generated code to an element
+ // of its generating .proto file.
+ repeated Annotation annotation = 1;
+ message Annotation {
+ // Identifies the element in the original source .proto file. This field
+ // is formatted the same as SourceCodeInfo.Location.path.
+ repeated int32 path = 1 [packed=true];
+
+ // Identifies the filesystem path to the original source .proto.
+ optional string source_file = 2;
+
+ // Identifies the starting offset in bytes in the generated code
+ // that relates to the identified object.
+ optional int32 begin = 3;
+
+ // Identifies the ending offset in bytes in the generated code that
+ // relates to the identified offset. The end offset should be one past
+ // the last relevant byte (so the length of the text = end - begin).
+ optional int32 end = 4;
+ }
+}
diff --git a/vendor/github.com/karalabe/hid/LICENSE.md b/vendor/github.com/karalabe/hid/LICENSE.md
deleted file mode 100644
index 230d1daeb..000000000
--- a/vendor/github.com/karalabe/hid/LICENSE.md
+++ /dev/null
@@ -1,8 +0,0 @@
-The components of `hid` are licensed as such:
-
- * `hidapi` is released under the [3-clause BSD](https://github.com/signal11/hidapi/blob/master/LICENSE-bsd.txt) license.
- * `libusb` is released under the [GNU LGPL 2.1](https://github.com/libusb/libusb/blob/master/COPYING)license.
- * `go.hid` is released under the [2-clause BSD](https://github.com/GeertJohan/go.hid/blob/master/LICENSE) license.
- * `gowchar` is released under the [3-clause BSD](https://github.com/orofarne/gowchar/blob/master/LICENSE) license.
-
-Given the above, `hid` is licensed under GNU LGPL 2.1 or later on Linux and 3-clause BSD on other platforms.
diff --git a/vendor/github.com/karalabe/hid/README.md b/vendor/github.com/karalabe/hid/README.md
deleted file mode 100644
index 2851ffe42..000000000
--- a/vendor/github.com/karalabe/hid/README.md
+++ /dev/null
@@ -1,53 +0,0 @@
-[![Travis][travisimg]][travisurl]
-[![AppVeyor][appveyorimg]][appveyorurl]
-[![GoDoc][docimg]][docurl]
-
-[travisimg]: https://travis-ci.org/karalabe/hid.svg?branch=master
-[travisurl]: https://travis-ci.org/karalabe/hid
-[appveyorimg]: https://ci.appveyor.com/api/projects/status/plroy54odykb0ch3/branch/master?svg=true
-[appveyorurl]: https://ci.appveyor.com/project/karalabe/hid
-[docimg]: https://godoc.org/github.com/karalabe/hid?status.svg
-[docurl]: https://godoc.org/github.com/karalabe/hid
-
-# Gopher Interface Devices (USB HID)
-
-The `hid` package is a cross platform library for accessing and communicating with USB Human Interface
-Devices (HID). It is an alternative package to [`gousb`](https://github.com/karalabe/gousb) for use
-cases where devices support this ligher mode of operation (e.g. input devices, hardware crypto wallets).
-
-The package wraps [`hidapi`](https://github.com/signal11/hidapi) for accessing OS specific USB HID APIs
-directly instead of using low level USB constructs, which might have permission issues on some platforms.
-On Linux the package also wraps [`libusb`](https://github.com/libusb/libusb). Both of these dependencies
-are vendored directly into the repository and wrapped using CGO, making the `hid` package self-contained
-and go-gettable.
-
-Supported platforms at the moment are Linux, macOS and Windows (exclude constraints are also specified
-for Android and iOS to allow smoother vendoring into cross platform projects).
-
-## Cross-compiling
-
-Using `go get` the embedded C library is compiled into the binary format of your host OS. Cross compiling to a different platform or architecture entails disabling CGO by default in Go, causing device enumeration `hid.Enumerate()` to yield no results.
-
-To cross compile a functional version of this library, you'll need to enable CGO during cross compilation via `CGO_ENABLED=1` and you'll need to install and set a cross compilation enabled C toolkit via `CC=your-cross-gcc`.
-
-## Acknowledgements
-
-Although the `hid` package is an implementation from scratch, it was heavily inspired by the existing
-[`go.hid`](https://github.com/GeertJohan/go.hid) library, which seems abandoned since 2015; is incompatible
-with Go 1.6+; and has various external dependencies. Given its inspirational roots, I thought it important
-to give credit to the author of said package too.
-
-Wide character support in the `hid` package is done via the [`gowchar`](https://github.com/orofarne/gowchar)
-library, unmaintained since 2013; non buildable with a modern Go release and failing `go vet` checks. As
-such, `gowchar` was also vendored in inline (copyright headers and origins preserved).
-
-## License
-
-The components of `hid` are licensed as such:
-
- * `hidapi` is released under the [3-clause BSD](https://github.com/signal11/hidapi/blob/master/LICENSE-bsd.txt) license.
- * `libusb` is released under the [GNU LGPL 2.1](https://github.com/libusb/libusb/blob/master/COPYING)license.
- * `go.hid` is released under the [2-clause BSD](https://github.com/GeertJohan/go.hid/blob/master/LICENSE) license.
- * `gowchar` is released under the [3-clause BSD](https://github.com/orofarne/gowchar/blob/master/LICENSE) license.
-
-Given the above, `hid` is licensed under GNU LGPL 2.1 or later on Linux and 3-clause BSD on other platforms.
diff --git a/vendor/github.com/karalabe/hid/hid.go b/vendor/github.com/karalabe/hid/hid.go
deleted file mode 100644
index 60a40b8c2..000000000
--- a/vendor/github.com/karalabe/hid/hid.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-package hid
-
-import "errors"
-
-// 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")
-
-// DeviceInfo is a hidapi info structure.
-type DeviceInfo 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
-}
diff --git a/vendor/github.com/karalabe/hid/hid_disabled.go b/vendor/github.com/karalabe/hid/hid_disabled.go
deleted file mode 100644
index 0f266ba58..000000000
--- a/vendor/github.com/karalabe/hid/hid_disabled.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-
-// +build !linux,!darwin,!windows ios !cgo
-
-package hid
-
-// Supported returns whether this platform is supported by the HID library or not.
-// The goal of this method is to allow programatically handling platforms that do
-// not support USB HID and not having to fall back to build constraints.
-func Supported() bool {
- return false
-}
-
-// Enumerate returns a list of all the HID devices attached to the system which
-// match the vendor and product id. On platforms that this file implements the
-// function is a noop and returns an empty list always.
-func Enumerate(vendorID uint16, productID uint16) []DeviceInfo {
- return nil
-}
-
-// Device is a live HID USB connected device handle. On platforms that this file
-// implements the type lacks the actual HID device and all methods are noop.
-type Device struct {
- DeviceInfo // Embed the infos for easier access
-}
-
-// Open connects to an HID device by its path name. On platforms that this file
-// implements the method just returns an error.
-func (info DeviceInfo) Open() (*Device, error) {
- return nil, ErrUnsupportedPlatform
-}
-
-// Close releases the HID USB device handle. On platforms that this file implements
-// the method is just a noop.
-func (dev *Device) Close() error { return nil }
-
-// Write sends an output report to a HID device. On platforms that this file
-// implements the method just returns an error.
-func (dev *Device) Write(b []byte) (int, error) {
- return 0, ErrUnsupportedPlatform
-}
-
-// Read retrieves an input report from a HID device. On platforms that this file
-// implements the method just returns an error.
-func (dev *Device) Read(b []byte) (int, error) {
- return 0, ErrUnsupportedPlatform
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.c
deleted file mode 100644
index 982560751..000000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.c
+++ /dev/null
@@ -1,728 +0,0 @@
-/*
- * poll_windows: poll compatibility wrapper for Windows
- * Copyright © 2012-2013 RealVNC Ltd.
- * Copyright © 2009-2010 Pete Batard <pete@akeo.ie>
- * With contributions from Michael Plante, Orin Eman et al.
- * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-/*
- * poll() and pipe() Windows compatibility layer for libusb 1.0
- *
- * The way this layer works is by using OVERLAPPED with async I/O transfers, as
- * OVERLAPPED have an associated event which is flagged for I/O completion.
- *
- * For USB pollable async I/O, you would typically:
- * - obtain a Windows HANDLE to a file or device that has been opened in
- * OVERLAPPED mode
- * - call usbi_create_fd with this handle to obtain a custom fd.
- * Note that if you need simultaneous R/W access, you need to call create_fd
- * twice, once in RW_READ and once in RW_WRITE mode to obtain 2 separate
- * pollable fds
- * - leave the core functions call the poll routine and flag POLLIN/POLLOUT
- *
- * The pipe pollable synchronous I/O works using the overlapped event associated
- * with a fake pipe. The read/write functions are only meant to be used in that
- * context.
- */
-#include <config.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "libusbi.h"
-
-// Uncomment to debug the polling layer
-//#define DEBUG_POLL_WINDOWS
-#if defined(DEBUG_POLL_WINDOWS)
-#define poll_dbg usbi_dbg
-#else
-// MSVC++ < 2005 cannot use a variadic argument and non MSVC
-// compilers produce warnings if parenthesis are omitted.
-#if defined(_MSC_VER) && (_MSC_VER < 1400)
-#define poll_dbg
-#else
-#define poll_dbg(...)
-#endif
-#endif
-
-#if defined(_PREFAST_)
-#pragma warning(disable:28719)
-#endif
-
-#define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0)
-
-// public fd data
-const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, NULL, NULL, RW_NONE};
-struct winfd poll_fd[MAX_FDS];
-// internal fd data
-struct {
- CRITICAL_SECTION mutex; // lock for fds
- // Additional variables for XP CancelIoEx partial emulation
- HANDLE original_handle;
- DWORD thread_id;
-} _poll_fd[MAX_FDS];
-
-// globals
-BOOLEAN is_polling_set = FALSE;
-LONG pipe_number = 0;
-static volatile LONG compat_spinlock = 0;
-
-#if !defined(_WIN32_WCE)
-// CancelIoEx, available on Vista and later only, provides the ability to cancel
-// a single transfer (OVERLAPPED) when used. As it may not be part of any of the
-// platform headers, we hook into the Kernel32 system DLL directly to seek it.
-static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
-#define Use_Duplicate_Handles (pCancelIoEx == NULL)
-
-static inline void setup_cancel_io(void)
-{
- HMODULE hKernel32 = GetModuleHandleA("KERNEL32");
- if (hKernel32 != NULL) {
- pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED))
- GetProcAddress(hKernel32, "CancelIoEx");
- }
- usbi_dbg("Will use CancelIo%s for I/O cancellation",
- Use_Duplicate_Handles?"":"Ex");
-}
-
-static inline BOOL cancel_io(int _index)
-{
- if ((_index < 0) || (_index >= MAX_FDS)) {
- return FALSE;
- }
-
- if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
- || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) {
- return TRUE;
- }
- if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) {
- // Cancel outstanding transfer via the specific callback
- (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer);
- return TRUE;
- }
- if (pCancelIoEx != NULL) {
- return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped);
- }
- if (_poll_fd[_index].thread_id == GetCurrentThreadId()) {
- return CancelIo(poll_fd[_index].handle);
- }
- usbi_warn(NULL, "Unable to cancel I/O that was started from another thread");
- return FALSE;
-}
-#else
-#define Use_Duplicate_Handles FALSE
-
-static __inline void setup_cancel_io()
-{
- // No setup needed on WinCE
-}
-
-static __inline BOOL cancel_io(int _index)
-{
- if ((_index < 0) || (_index >= MAX_FDS)) {
- return FALSE;
- }
- if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
- || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) {
- return TRUE;
- }
- if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) {
- // Cancel outstanding transfer via the specific callback
- (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer);
- }
- return TRUE;
-}
-#endif
-
-// Init
-void init_polling(void)
-{
- int i;
-
- while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
- SleepEx(0, TRUE);
- }
- if (!is_polling_set) {
- setup_cancel_io();
- for (i=0; i<MAX_FDS; i++) {
- poll_fd[i] = INVALID_WINFD;
- _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
- _poll_fd[i].thread_id = 0;
- InitializeCriticalSection(&_poll_fd[i].mutex);
- }
- is_polling_set = TRUE;
- }
- InterlockedExchange((LONG *)&compat_spinlock, 0);
-}
-
-// Internal function to retrieve the table index (and lock the fd mutex)
-static int _fd_to_index_and_lock(int fd)
-{
- int i;
-
- if (fd < 0)
- return -1;
-
- for (i=0; i<MAX_FDS; i++) {
- if (poll_fd[i].fd == fd) {
- EnterCriticalSection(&_poll_fd[i].mutex);
- // fd might have changed before we got to critical
- if (poll_fd[i].fd != fd) {
- LeaveCriticalSection(&_poll_fd[i].mutex);
- continue;
- }
- return i;
- }
- }
- return -1;
-}
-
-static OVERLAPPED *create_overlapped(void)
-{
- OVERLAPPED *overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED));
- if (overlapped == NULL) {
- return NULL;
- }
- overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- if(overlapped->hEvent == NULL) {
- free (overlapped);
- return NULL;
- }
- return overlapped;
-}
-
-static void free_overlapped(OVERLAPPED *overlapped)
-{
- if (overlapped == NULL)
- return;
-
- if ( (overlapped->hEvent != 0)
- && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) {
- CloseHandle(overlapped->hEvent);
- }
- free(overlapped);
-}
-
-void exit_polling(void)
-{
- int i;
-
- while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
- SleepEx(0, TRUE);
- }
- if (is_polling_set) {
- is_polling_set = FALSE;
-
- for (i=0; i<MAX_FDS; i++) {
- // Cancel any async I/O (handle can be invalid)
- cancel_io(i);
- // If anything was pending on that I/O, it should be
- // terminating, and we should be able to access the fd
- // mutex lock before too long
- EnterCriticalSection(&_poll_fd[i].mutex);
- free_overlapped(poll_fd[i].overlapped);
- if (Use_Duplicate_Handles) {
- // Close duplicate handle
- if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) {
- CloseHandle(poll_fd[i].handle);
- }
- }
- poll_fd[i] = INVALID_WINFD;
- LeaveCriticalSection(&_poll_fd[i].mutex);
- DeleteCriticalSection(&_poll_fd[i].mutex);
- }
- }
- InterlockedExchange((LONG *)&compat_spinlock, 0);
-}
-
-/*
- * Create a fake pipe.
- * As libusb only uses pipes for signaling, all we need from a pipe is an
- * event. To that extent, we create a single wfd and overlapped as a means
- * to access that event.
- */
-int usbi_pipe(int filedes[2])
-{
- int i;
- OVERLAPPED* overlapped;
-
- CHECK_INIT_POLLING;
-
- overlapped = create_overlapped();
-
- if (overlapped == NULL) {
- return -1;
- }
- // The overlapped must have status pending for signaling to work in poll
- overlapped->Internal = STATUS_PENDING;
- overlapped->InternalHigh = 0;
-
- for (i=0; i<MAX_FDS; i++) {
- if (poll_fd[i].fd < 0) {
- EnterCriticalSection(&_poll_fd[i].mutex);
- // fd might have been allocated before we got to critical
- if (poll_fd[i].fd >= 0) {
- LeaveCriticalSection(&_poll_fd[i].mutex);
- continue;
- }
-
- // Use index as the unique fd number
- poll_fd[i].fd = i;
- // Read end of the "pipe"
- filedes[0] = poll_fd[i].fd;
- // We can use the same handle for both ends
- filedes[1] = filedes[0];
-
- poll_fd[i].handle = DUMMY_HANDLE;
- poll_fd[i].overlapped = overlapped;
- // There's no polling on the write end, so we just use READ for our needs
- poll_fd[i].rw = RW_READ;
- _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
- LeaveCriticalSection(&_poll_fd[i].mutex);
- return 0;
- }
- }
- free_overlapped(overlapped);
- return -1;
-}
-
-/*
- * Create both an fd and an OVERLAPPED from an open Windows handle, so that
- * it can be used with our polling function
- * The handle MUST support overlapped transfers (usually requires CreateFile
- * with FILE_FLAG_OVERLAPPED)
- * Return a pollable file descriptor struct, or INVALID_WINFD on error
- *
- * Note that the fd returned by this function is a per-transfer fd, rather
- * than a per-session fd and cannot be used for anything else but our
- * custom functions (the fd itself points to the NUL: device)
- * if you plan to do R/W on the same handle, you MUST create 2 fds: one for
- * read and one for write. Using a single R/W fd is unsupported and will
- * produce unexpected results
- */
-struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct usbi_transfer *itransfer, cancel_transfer *cancel_fn)
-{
- int i;
- struct winfd wfd = INVALID_WINFD;
- OVERLAPPED* overlapped = NULL;
-
- CHECK_INIT_POLLING;
-
- if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) {
- return INVALID_WINFD;
- }
-
- wfd.itransfer = itransfer;
- wfd.cancel_fn = cancel_fn;
-
- if ((access_mode != RW_READ) && (access_mode != RW_WRITE)) {
- usbi_warn(NULL, "only one of RW_READ or RW_WRITE are supported. "
- "If you want to poll for R/W simultaneously, create multiple fds from the same handle.");
- return INVALID_WINFD;
- }
- if (access_mode == RW_READ) {
- wfd.rw = RW_READ;
- } else {
- wfd.rw = RW_WRITE;
- }
-
- overlapped = create_overlapped();
- if(overlapped == NULL) {
- return INVALID_WINFD;
- }
-
- for (i=0; i<MAX_FDS; i++) {
- if (poll_fd[i].fd < 0) {
- EnterCriticalSection(&_poll_fd[i].mutex);
- // fd might have been removed before we got to critical
- if (poll_fd[i].fd >= 0) {
- LeaveCriticalSection(&_poll_fd[i].mutex);
- continue;
- }
- // Use index as the unique fd number
- wfd.fd = i;
- // Attempt to emulate some of the CancelIoEx behaviour on platforms
- // that don't have it
- if (Use_Duplicate_Handles) {
- _poll_fd[i].thread_id = GetCurrentThreadId();
- if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
- &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
- usbi_dbg("could not duplicate handle for CancelIo - using original one");
- wfd.handle = handle;
- // Make sure we won't close the original handle on fd deletion then
- _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
- } else {
- _poll_fd[i].original_handle = handle;
- }
- } else {
- wfd.handle = handle;
- }
- wfd.overlapped = overlapped;
- memcpy(&poll_fd[i], &wfd, sizeof(struct winfd));
- LeaveCriticalSection(&_poll_fd[i].mutex);
- return wfd;
- }
- }
- free_overlapped(overlapped);
- return INVALID_WINFD;
-}
-
-static void _free_index(int _index)
-{
- // Cancel any async IO (Don't care about the validity of our handles for this)
- cancel_io(_index);
- // close the duplicate handle (if we have an actual duplicate)
- if (Use_Duplicate_Handles) {
- if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) {
- CloseHandle(poll_fd[_index].handle);
- }
- _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE;
- _poll_fd[_index].thread_id = 0;
- }
- free_overlapped(poll_fd[_index].overlapped);
- poll_fd[_index] = INVALID_WINFD;
-}
-
-/*
- * Release a pollable file descriptor.
- *
- * Note that the associated Windows handle is not closed by this call
- */
-void usbi_free_fd(struct winfd *wfd)
-{
- int _index;
-
- CHECK_INIT_POLLING;
-
- _index = _fd_to_index_and_lock(wfd->fd);
- if (_index < 0) {
- return;
- }
- _free_index(_index);
- *wfd = INVALID_WINFD;
- LeaveCriticalSection(&_poll_fd[_index].mutex);
-}
-
-/*
- * The functions below perform various conversions between fd, handle and OVERLAPPED
- */
-struct winfd fd_to_winfd(int fd)
-{
- int i;
- struct winfd wfd;
-
- CHECK_INIT_POLLING;
-
- if (fd < 0)
- return INVALID_WINFD;
-
- for (i=0; i<MAX_FDS; i++) {
- if (poll_fd[i].fd == fd) {
- EnterCriticalSection(&_poll_fd[i].mutex);
- // fd might have been deleted before we got to critical
- if (poll_fd[i].fd != fd) {
- LeaveCriticalSection(&_poll_fd[i].mutex);
- continue;
- }
- memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
- LeaveCriticalSection(&_poll_fd[i].mutex);
- return wfd;
- }
- }
- return INVALID_WINFD;
-}
-
-struct winfd handle_to_winfd(HANDLE handle)
-{
- int i;
- struct winfd wfd;
-
- CHECK_INIT_POLLING;
-
- if ((handle == 0) || (handle == INVALID_HANDLE_VALUE))
- return INVALID_WINFD;
-
- for (i=0; i<MAX_FDS; i++) {
- if (poll_fd[i].handle == handle) {
- EnterCriticalSection(&_poll_fd[i].mutex);
- // fd might have been deleted before we got to critical
- if (poll_fd[i].handle != handle) {
- LeaveCriticalSection(&_poll_fd[i].mutex);
- continue;
- }
- memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
- LeaveCriticalSection(&_poll_fd[i].mutex);
- return wfd;
- }
- }
- return INVALID_WINFD;
-}
-
-struct winfd overlapped_to_winfd(OVERLAPPED* overlapped)
-{
- int i;
- struct winfd wfd;
-
- CHECK_INIT_POLLING;
-
- if (overlapped == NULL)
- return INVALID_WINFD;
-
- for (i=0; i<MAX_FDS; i++) {
- if (poll_fd[i].overlapped == overlapped) {
- EnterCriticalSection(&_poll_fd[i].mutex);
- // fd might have been deleted before we got to critical
- if (poll_fd[i].overlapped != overlapped) {
- LeaveCriticalSection(&_poll_fd[i].mutex);
- continue;
- }
- memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
- LeaveCriticalSection(&_poll_fd[i].mutex);
- return wfd;
- }
- }
- return INVALID_WINFD;
-}
-
-/*
- * POSIX poll equivalent, using Windows OVERLAPPED
- * Currently, this function only accepts one of POLLIN or POLLOUT per fd
- * (but you can create multiple fds from the same handle for read and write)
- */
-int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout)
-{
- unsigned i;
- int _index, object_index, triggered;
- HANDLE *handles_to_wait_on;
- int *handle_to_index;
- DWORD nb_handles_to_wait_on = 0;
- DWORD ret;
-
- CHECK_INIT_POLLING;
-
- triggered = 0;
- handles_to_wait_on = (HANDLE*) calloc(nfds+1, sizeof(HANDLE)); // +1 for fd_update
- handle_to_index = (int*) calloc(nfds, sizeof(int));
- if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) {
- errno = ENOMEM;
- triggered = -1;
- goto poll_exit;
- }
-
- for (i = 0; i < nfds; ++i) {
- fds[i].revents = 0;
-
- // Only one of POLLIN or POLLOUT can be selected with this version of poll (not both)
- if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) {
- fds[i].revents |= POLLERR;
- errno = EACCES;
- usbi_warn(NULL, "unsupported set of events");
- triggered = -1;
- goto poll_exit;
- }
-
- _index = _fd_to_index_and_lock(fds[i].fd);
- poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[_index].fd, poll_fd[_index].overlapped, fds[i].events);
-
- if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
- || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) {
- fds[i].revents |= POLLNVAL | POLLERR;
- errno = EBADF;
- if (_index >= 0) {
- LeaveCriticalSection(&_poll_fd[_index].mutex);
- }
- usbi_warn(NULL, "invalid fd");
- triggered = -1;
- goto poll_exit;
- }
-
- // IN or OUT must match our fd direction
- if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) {
- fds[i].revents |= POLLNVAL | POLLERR;
- errno = EBADF;
- usbi_warn(NULL, "attempted POLLIN on fd without READ access");
- LeaveCriticalSection(&_poll_fd[_index].mutex);
- triggered = -1;
- goto poll_exit;
- }
-
- if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) {
- fds[i].revents |= POLLNVAL | POLLERR;
- errno = EBADF;
- usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access");
- LeaveCriticalSection(&_poll_fd[_index].mutex);
- triggered = -1;
- goto poll_exit;
- }
-
- // The following macro only works if overlapped I/O was reported pending
- if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped))
- || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) {
- poll_dbg(" completed");
- // checks above should ensure this works:
- fds[i].revents = fds[i].events;
- triggered++;
- } else {
- handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent;
- handle_to_index[nb_handles_to_wait_on] = i;
- nb_handles_to_wait_on++;
- }
- LeaveCriticalSection(&_poll_fd[_index].mutex);
- }
-
- // If nothing was triggered, wait on all fds that require it
- if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) {
- if (timeout < 0) {
- poll_dbg("starting infinite wait for %u handles...", (unsigned int)nb_handles_to_wait_on);
- } else {
- poll_dbg("starting %d ms wait for %u handles...", timeout, (unsigned int)nb_handles_to_wait_on);
- }
- ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on,
- FALSE, (timeout<0)?INFINITE:(DWORD)timeout);
- object_index = ret-WAIT_OBJECT_0;
- if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) {
- poll_dbg(" completed after wait");
- i = handle_to_index[object_index];
- _index = _fd_to_index_and_lock(fds[i].fd);
- fds[i].revents = fds[i].events;
- triggered++;
- if (_index >= 0) {
- LeaveCriticalSection(&_poll_fd[_index].mutex);
- }
- } else if (ret == WAIT_TIMEOUT) {
- poll_dbg(" timed out");
- triggered = 0; // 0 = timeout
- } else {
- errno = EIO;
- triggered = -1; // error
- }
- }
-
-poll_exit:
- if (handles_to_wait_on != NULL) {
- free(handles_to_wait_on);
- }
- if (handle_to_index != NULL) {
- free(handle_to_index);
- }
- return triggered;
-}
-
-/*
- * close a fake pipe fd
- */
-int usbi_close(int fd)
-{
- int _index;
- int r = -1;
-
- CHECK_INIT_POLLING;
-
- _index = _fd_to_index_and_lock(fd);
-
- if (_index < 0) {
- errno = EBADF;
- } else {
- free_overlapped(poll_fd[_index].overlapped);
- poll_fd[_index] = INVALID_WINFD;
- LeaveCriticalSection(&_poll_fd[_index].mutex);
- }
- return r;
-}
-
-/*
- * synchronous write for fake "pipe" signaling
- */
-ssize_t usbi_write(int fd, const void *buf, size_t count)
-{
- int _index;
- UNUSED(buf);
-
- CHECK_INIT_POLLING;
-
- if (count != sizeof(unsigned char)) {
- usbi_err(NULL, "this function should only used for signaling");
- return -1;
- }
-
- _index = _fd_to_index_and_lock(fd);
-
- if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) {
- errno = EBADF;
- if (_index >= 0) {
- LeaveCriticalSection(&_poll_fd[_index].mutex);
- }
- return -1;
- }
-
- poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, (unsigned int)GetCurrentThreadId());
- SetEvent(poll_fd[_index].overlapped->hEvent);
- poll_fd[_index].overlapped->Internal = STATUS_WAIT_0;
- // If two threads write on the pipe at the same time, we need to
- // process two separate reads => use the overlapped as a counter
- poll_fd[_index].overlapped->InternalHigh++;
-
- LeaveCriticalSection(&_poll_fd[_index].mutex);
- return sizeof(unsigned char);
-}
-
-/*
- * synchronous read for fake "pipe" signaling
- */
-ssize_t usbi_read(int fd, void *buf, size_t count)
-{
- int _index;
- ssize_t r = -1;
- UNUSED(buf);
-
- CHECK_INIT_POLLING;
-
- if (count != sizeof(unsigned char)) {
- usbi_err(NULL, "this function should only used for signaling");
- return -1;
- }
-
- _index = _fd_to_index_and_lock(fd);
-
- if (_index < 0) {
- errno = EBADF;
- return -1;
- }
-
- if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) {
- usbi_warn(NULL, "waiting for event failed: %u", (unsigned int)GetLastError());
- errno = EIO;
- goto out;
- }
-
- poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, (unsigned int)GetCurrentThreadId());
- poll_fd[_index].overlapped->InternalHigh--;
- // Don't reset unless we don't have any more events to process
- if (poll_fd[_index].overlapped->InternalHigh <= 0) {
- ResetEvent(poll_fd[_index].overlapped->hEvent);
- poll_fd[_index].overlapped->Internal = STATUS_PENDING;
- }
-
- r = sizeof(unsigned char);
-
-out:
- LeaveCriticalSection(&_poll_fd[_index].mutex);
- return r;
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.h
deleted file mode 100644
index 4c1514ea6..000000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * libusb synchronization using POSIX Threads
- *
- * Copyright © 2010 Peter Stuge <peter@stuge.se>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef LIBUSB_THREADS_POSIX_H
-#define LIBUSB_THREADS_POSIX_H
-
-#include <pthread.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#define usbi_mutex_static_t pthread_mutex_t
-#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
-#define usbi_mutex_static_lock pthread_mutex_lock
-#define usbi_mutex_static_unlock pthread_mutex_unlock
-
-#define usbi_mutex_t pthread_mutex_t
-#define usbi_mutex_init(mutex) pthread_mutex_init((mutex), NULL)
-#define usbi_mutex_lock pthread_mutex_lock
-#define usbi_mutex_unlock pthread_mutex_unlock
-#define usbi_mutex_trylock pthread_mutex_trylock
-#define usbi_mutex_destroy pthread_mutex_destroy
-
-#define usbi_cond_t pthread_cond_t
-#define usbi_cond_init(cond) pthread_cond_init((cond), NULL)
-#define usbi_cond_wait pthread_cond_wait
-#define usbi_cond_broadcast pthread_cond_broadcast
-#define usbi_cond_destroy pthread_cond_destroy
-
-#define usbi_tls_key_t pthread_key_t
-#define usbi_tls_key_create(key) pthread_key_create((key), NULL)
-#define usbi_tls_key_get pthread_getspecific
-#define usbi_tls_key_set pthread_setspecific
-#define usbi_tls_key_delete pthread_key_delete
-
-int usbi_get_tid(void);
-
-#endif /* LIBUSB_THREADS_POSIX_H */
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.c
deleted file mode 100644
index 7c2e52dba..000000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * libusb synchronization on Microsoft Windows
- *
- * Copyright © 2010 Michael Plante <michael.plante@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <config.h>
-
-#include <objbase.h>
-#include <errno.h>
-
-#include "libusbi.h"
-
-struct usbi_cond_perthread {
- struct list_head list;
- DWORD tid;
- HANDLE event;
-};
-
-int usbi_mutex_static_lock(usbi_mutex_static_t *mutex)
-{
- if (!mutex)
- return EINVAL;
- while (InterlockedExchange(mutex, 1) == 1)
- SleepEx(0, TRUE);
- return 0;
-}
-
-int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex)
-{
- if (!mutex)
- return EINVAL;
- InterlockedExchange(mutex, 0);
- return 0;
-}
-
-int usbi_mutex_init(usbi_mutex_t *mutex)
-{
- if (!mutex)
- return EINVAL;
- *mutex = CreateMutex(NULL, FALSE, NULL);
- if (!*mutex)
- return ENOMEM;
- return 0;
-}
-
-int usbi_mutex_lock(usbi_mutex_t *mutex)
-{
- DWORD result;
-
- if (!mutex)
- return EINVAL;
- result = WaitForSingleObject(*mutex, INFINITE);
- if (result == WAIT_OBJECT_0 || result == WAIT_ABANDONED)
- return 0; // acquired (ToDo: check that abandoned is ok)
- else
- return EINVAL; // don't know how this would happen
- // so don't know proper errno
-}
-
-int usbi_mutex_unlock(usbi_mutex_t *mutex)
-{
- if (!mutex)
- return EINVAL;
- if (ReleaseMutex(*mutex))
- return 0;
- else
- return EPERM;
-}
-
-int usbi_mutex_trylock(usbi_mutex_t *mutex)
-{
- DWORD result;
-
- if (!mutex)
- return EINVAL;
- result = WaitForSingleObject(*mutex, 0);
- if (result == WAIT_OBJECT_0 || result == WAIT_ABANDONED)
- return 0; // acquired (ToDo: check that abandoned is ok)
- else if (result == WAIT_TIMEOUT)
- return EBUSY;
- else
- return EINVAL; // don't know how this would happen
- // so don't know proper error
-}
-
-int usbi_mutex_destroy(usbi_mutex_t *mutex)
-{
- // It is not clear if CloseHandle failure is due to failure to unlock.
- // If so, this should be errno=EBUSY.
- if (!mutex || !CloseHandle(*mutex))
- return EINVAL;
- *mutex = NULL;
- return 0;
-}
-
-int usbi_cond_init(usbi_cond_t *cond)
-{
- if (!cond)
- return EINVAL;
- list_init(&cond->waiters);
- list_init(&cond->not_waiting);
- return 0;
-}
-
-int usbi_cond_destroy(usbi_cond_t *cond)
-{
- // This assumes no one is using this anymore. The check MAY NOT BE safe.
- struct usbi_cond_perthread *pos, *next_pos;
-
- if(!cond)
- return EINVAL;
- if (!list_empty(&cond->waiters))
- return EBUSY; // (!see above!)
- list_for_each_entry_safe(pos, next_pos, &cond->not_waiting, list, struct usbi_cond_perthread) {
- CloseHandle(pos->event);
- list_del(&pos->list);
- free(pos);
- }
- return 0;
-}
-
-int usbi_cond_broadcast(usbi_cond_t *cond)
-{
- // Assumes mutex is locked; this is not in keeping with POSIX spec, but
- // libusb does this anyway, so we simplify by not adding more sync
- // primitives to the CV definition!
- int fail = 0;
- struct usbi_cond_perthread *pos;
-
- if (!cond)
- return EINVAL;
- list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread) {
- if (!SetEvent(pos->event))
- fail = 1;
- }
- // The wait function will remove its respective item from the list.
- return fail ? EINVAL : 0;
-}
-
-__inline static int usbi_cond_intwait(usbi_cond_t *cond,
- usbi_mutex_t *mutex, DWORD timeout_ms)
-{
- struct usbi_cond_perthread *pos;
- int r, found = 0;
- DWORD r2, tid = GetCurrentThreadId();
-
- if (!cond || !mutex)
- return EINVAL;
- list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) {
- if(tid == pos->tid) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- pos = calloc(1, sizeof(struct usbi_cond_perthread));
- if (!pos)
- return ENOMEM; // This errno is not POSIX-allowed.
- pos->tid = tid;
- pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset.
- if (!pos->event) {
- free(pos);
- return ENOMEM;
- }
- list_add(&pos->list, &cond->not_waiting);
- }
-
- list_del(&pos->list); // remove from not_waiting list.
- list_add(&pos->list, &cond->waiters);
-
- r = usbi_mutex_unlock(mutex);
- if (r)
- return r;
-
- r2 = WaitForSingleObject(pos->event, timeout_ms);
- r = usbi_mutex_lock(mutex);
- if (r)
- return r;
-
- list_del(&pos->list);
- list_add(&pos->list, &cond->not_waiting);
-
- if (r2 == WAIT_OBJECT_0)
- return 0;
- else if (r2 == WAIT_TIMEOUT)
- return ETIMEDOUT;
- else
- return EINVAL;
-}
-// N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot!
-int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
-{
- return usbi_cond_intwait(cond, mutex, INFINITE);
-}
-
-int usbi_cond_timedwait(usbi_cond_t *cond,
- usbi_mutex_t *mutex, const struct timeval *tv)
-{
- DWORD millis;
-
- millis = (DWORD)(tv->tv_sec * 1000) + (tv->tv_usec / 1000);
- /* round up to next millisecond */
- if (tv->tv_usec % 1000)
- millis++;
- return usbi_cond_intwait(cond, mutex, millis);
-}
-
-int usbi_tls_key_create(usbi_tls_key_t *key)
-{
- if (!key)
- return EINVAL;
- *key = TlsAlloc();
- if (*key == TLS_OUT_OF_INDEXES)
- return ENOMEM;
- else
- return 0;
-}
-
-void *usbi_tls_key_get(usbi_tls_key_t key)
-{
- return TlsGetValue(key);
-}
-
-int usbi_tls_key_set(usbi_tls_key_t key, void *value)
-{
- if (TlsSetValue(key, value))
- return 0;
- else
- return EINVAL;
-}
-
-int usbi_tls_key_delete(usbi_tls_key_t key)
-{
- if (TlsFree(key))
- return 0;
- else
- return EINVAL;
-}
-
-int usbi_get_tid(void)
-{
- return (int)GetCurrentThreadId();
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.h
deleted file mode 100644
index 52ea8708b..000000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Windows backend common header for libusb 1.0
- *
- * This file brings together header code common between
- * the desktop Windows backends.
- * Copyright © 2012-2013 RealVNC Ltd.
- * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
- * With contributions from Michael Plante, Orin Eman et al.
- * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
- * Major code testing contribution by Xiaofan Chen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#pragma once
-
-// Missing from MinGW
-#if !defined(FACILITY_SETUPAPI)
-#define FACILITY_SETUPAPI 15
-#endif
-
-typedef struct USB_CONFIGURATION_DESCRIPTOR {
- UCHAR bLength;
- UCHAR bDescriptorType;
- USHORT wTotalLength;
- UCHAR bNumInterfaces;
- UCHAR bConfigurationValue;
- UCHAR iConfiguration;
- UCHAR bmAttributes;
- UCHAR MaxPower;
-} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
-
-typedef struct libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
-
-int windows_common_init(struct libusb_context *ctx);
-void windows_common_exit(void);
-
-unsigned long htab_hash(const char *str);
-int windows_clock_gettime(int clk_id, struct timespec *tp);
-
-void windows_clear_transfer_priv(struct usbi_transfer *itransfer);
-int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size);
-struct winfd *windows_get_fd(struct usbi_transfer *transfer);
-void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size);
-
-void windows_handle_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size);
-int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready);
-
-#if defined(ENABLE_LOGGING)
-const char *windows_error_str(DWORD error_code);
-#endif
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.c
deleted file mode 100644
index 0dce0ea6c..000000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.c
+++ /dev/null
@@ -1,4290 +0,0 @@
-/*
- * windows backend for libusb 1.0
- * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
- * With contributions from Michael Plante, Orin Eman et al.
- * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
- * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software
- * Hash table functions adapted from glibc, by Ulrich Drepper et al.
- * Major code testing contribution by Xiaofan Chen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <config.h>
-
-#if !defined(USE_USBDK)
-
-#include <windows.h>
-#include <setupapi.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <process.h>
-#include <stdio.h>
-#include <inttypes.h>
-#include <objbase.h>
-#include <winioctl.h>
-
-#include "libusbi.h"
-#include "poll_windows.h"
-#include "windows_winusb.h"
-
-#define HANDLE_VALID(h) (((h) != 0) && ((h) != INVALID_HANDLE_VALUE))
-
-// The 2 macros below are used in conjunction with safe loops.
-#define LOOP_CHECK(fcall) \
- { \
- r = fcall; \
- if (r != LIBUSB_SUCCESS) \
- continue; \
- }
-#define LOOP_BREAK(err) \
- { \
- r = err; \
- continue; \
- }
-
-// WinUSB-like API prototypes
-static int winusbx_init(int sub_api, struct libusb_context *ctx);
-static int winusbx_exit(int sub_api);
-static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle);
-static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle);
-static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting);
-static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
-static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
-// HID API prototypes
-static int hid_init(int sub_api, struct libusb_context *ctx);
-static int hid_exit(int sub_api);
-static int hid_open(int sub_api, struct libusb_device_handle *dev_handle);
-static void hid_close(int sub_api, struct libusb_device_handle *dev_handle);
-static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting);
-static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer);
-static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
-static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
-// Composite API prototypes
-static int composite_init(int sub_api, struct libusb_context *ctx);
-static int composite_exit(int sub_api);
-static int composite_open(int sub_api, struct libusb_device_handle *dev_handle);
-static void composite_close(int sub_api, struct libusb_device_handle *dev_handle);
-static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting);
-static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer);
-static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer);
-static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
-static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
-
-
-// Global variables
-int windows_version = WINDOWS_UNDEFINED;
-static char windows_version_str[128] = "Undefined";
-// Concurrency
-static int concurrent_usage = -1;
-static usbi_mutex_t autoclaim_lock;
-// API globals
-#define CHECK_WINUSBX_AVAILABLE(sub_api) \
- do { \
- if (sub_api == SUB_API_NOTSET) \
- sub_api = priv->sub_api; \
- if (!WinUSBX[sub_api].initialized) \
- return LIBUSB_ERROR_ACCESS; \
- } while(0)
-
-static HMODULE WinUSBX_handle = NULL;
-static struct winusb_interface WinUSBX[SUB_API_MAX];
-static const char *sub_api_name[SUB_API_MAX] = WINUSBX_DRV_NAMES;
-
-static bool api_hid_available = false;
-#define CHECK_HID_AVAILABLE \
- do { \
- if (!api_hid_available) \
- return LIBUSB_ERROR_ACCESS; \
- } while (0)
-
-static inline BOOLEAN guid_eq(const GUID *guid1, const GUID *guid2)
-{
- if ((guid1 != NULL) && (guid2 != NULL))
- return (memcmp(guid1, guid2, sizeof(GUID)) == 0);
-
- return false;
-}
-
-#if defined(ENABLE_LOGGING)
-static char *guid_to_string(const GUID *guid)
-{
- static char guid_string[MAX_GUID_STRING_LENGTH];
-
- if (guid == NULL)
- return NULL;
-
- sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
- (unsigned int)guid->Data1, guid->Data2, guid->Data3,
- guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
- guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
-
- return guid_string;
-}
-#endif
-
-/*
- * Sanitize Microsoft's paths: convert to uppercase, add prefix and fix backslashes.
- * Return an allocated sanitized string or NULL on error.
- */
-static char *sanitize_path(const char *path)
-{
- const char root_prefix[] = { '\\', '\\', '.', '\\' };
- size_t j, size;
- char *ret_path;
- size_t add_root = 0;
-
- if (path == NULL)
- return NULL;
-
- size = strlen(path) + 1;
-
- // Microsoft indiscriminately uses '\\?\', '\\.\', '##?#" or "##.#" for root prefixes.
- if (!((size > 3) && (((path[0] == '\\') && (path[1] == '\\') && (path[3] == '\\'))
- || ((path[0] == '#') && (path[1] == '#') && (path[3] == '#'))))) {
- add_root = sizeof(root_prefix);
- size += add_root;
- }
-
- ret_path = malloc(size);
- if (ret_path == NULL)
- return NULL;
-
- strcpy(&ret_path[add_root], path);
-
- // Ensure consistency with root prefix
- memcpy(ret_path, root_prefix, sizeof(root_prefix));
-
- // Same goes for '\' and '#' after the root prefix. Ensure '#' is used
- for (j = sizeof(root_prefix); j < size; j++) {
- ret_path[j] = (char)toupper((int)ret_path[j]); // Fix case too
- if (ret_path[j] == '\\')
- ret_path[j] = '#';
- }
-
- return ret_path;
-}
-
-/*
- * Cfgmgr32, OLE32 and SetupAPI DLL functions
- */
-static int init_dlls(void)
-{
- DLL_GET_HANDLE(Cfgmgr32);
- DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, TRUE);
- DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, TRUE);
- DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Sibling, TRUE);
- DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Device_IDA, TRUE);
-
- // Prefixed to avoid conflict with header files
- DLL_GET_HANDLE(AdvAPI32);
- DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, TRUE);
- DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, TRUE);
-
- DLL_GET_HANDLE(Kernel32);
- DLL_LOAD_FUNC_PREFIXED(Kernel32, p, IsWow64Process, FALSE);
-
- DLL_GET_HANDLE(OLE32);
- DLL_LOAD_FUNC_PREFIXED(OLE32, p, CLSIDFromString, TRUE);
-
- DLL_GET_HANDLE(SetupAPI);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, TRUE);
-
- return LIBUSB_SUCCESS;
-}
-
-static void exit_dlls(void)
-{
- DLL_FREE_HANDLE(Cfgmgr32);
- DLL_FREE_HANDLE(AdvAPI32);
- DLL_FREE_HANDLE(Kernel32);
- DLL_FREE_HANDLE(OLE32);
- DLL_FREE_HANDLE(SetupAPI);
-}
-
-/*
- * enumerate interfaces for the whole USB class
- *
- * Parameters:
- * dev_info: a pointer to a dev_info list
- * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed)
- * usb_class: the generic USB class for which to retrieve interface details
- * index: zero based index of the interface in the device info list
- *
- * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA
- * structure returned and call this function repeatedly using the same guid (with an
- * incremented index starting at zero) until all interfaces have been returned.
- */
-static bool get_devinfo_data(struct libusb_context *ctx,
- HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const char *usb_class, unsigned _index)
-{
- if (_index <= 0) {
- *dev_info = pSetupDiGetClassDevsA(NULL, usb_class, NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES);
- if (*dev_info == INVALID_HANDLE_VALUE)
- return false;
- }
-
- dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
- if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) {
- if (GetLastError() != ERROR_NO_MORE_ITEMS)
- usbi_err(ctx, "Could not obtain device info data for index %u: %s",
- _index, windows_error_str(0));
-
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return false;
- }
- return true;
-}
-
-/*
- * enumerate interfaces for a specific GUID
- *
- * Parameters:
- * dev_info: a pointer to a dev_info list
- * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed)
- * guid: the GUID for which to retrieve interface details
- * index: zero based index of the interface in the device info list
- *
- * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA
- * structure returned and call this function repeatedly using the same guid (with an
- * incremented index starting at zero) until all interfaces have been returned.
- */
-static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details(struct libusb_context *ctx,
- HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID *guid, unsigned _index)
-{
- SP_DEVICE_INTERFACE_DATA dev_interface_data;
- SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details;
- DWORD size;
-
- if (_index <= 0)
- *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
-
- if (dev_info_data != NULL) {
- dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
- if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) {
- if (GetLastError() != ERROR_NO_MORE_ITEMS)
- usbi_err(ctx, "Could not obtain device info data for index %u: %s",
- _index, windows_error_str(0));
-
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return NULL;
- }
- }
-
- dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, guid, _index, &dev_interface_data)) {
- if (GetLastError() != ERROR_NO_MORE_ITEMS)
- usbi_err(ctx, "Could not obtain interface data for index %u: %s",
- _index, windows_error_str(0));
-
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return NULL;
- }
-
- // Read interface data (dummy + actual) to access the device path
- if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) {
- // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER
- if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- usbi_err(ctx, "could not access interface data (dummy) for index %u: %s",
- _index, windows_error_str(0));
- goto err_exit;
- }
- } else {
- usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong.");
- goto err_exit;
- }
-
- dev_interface_details = calloc(1, size);
- if (dev_interface_details == NULL) {
- usbi_err(ctx, "could not allocate interface data for index %u.", _index);
- goto err_exit;
- }
-
- dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
- if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data,
- dev_interface_details, size, &size, NULL)) {
- usbi_err(ctx, "could not access interface data (actual) for index %u: %s",
- _index, windows_error_str(0));
- }
-
- return dev_interface_details;
-
-err_exit:
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return NULL;
-}
-
-/* For libusb0 filter */
-static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details_filter(struct libusb_context *ctx,
- HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID *guid, unsigned _index, char *filter_path)
-{
- SP_DEVICE_INTERFACE_DATA dev_interface_data;
- SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details;
- DWORD size;
-
- if (_index <= 0)
- *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
-
- if (dev_info_data != NULL) {
- dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
- if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) {
- if (GetLastError() != ERROR_NO_MORE_ITEMS)
- usbi_err(ctx, "Could not obtain device info data for index %u: %s",
- _index, windows_error_str(0));
-
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return NULL;
- }
- }
-
- dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, guid, _index, &dev_interface_data)) {
- if (GetLastError() != ERROR_NO_MORE_ITEMS)
- usbi_err(ctx, "Could not obtain interface data for index %u: %s",
- _index, windows_error_str(0));
-
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return NULL;
- }
-
- // Read interface data (dummy + actual) to access the device path
- if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) {
- // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER
- if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- usbi_err(ctx, "could not access interface data (dummy) for index %u: %s",
- _index, windows_error_str(0));
- goto err_exit;
- }
- } else {
- usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong.");
- goto err_exit;
- }
-
- dev_interface_details = calloc(1, size);
- if (dev_interface_details == NULL) {
- usbi_err(ctx, "could not allocate interface data for index %u.", _index);
- goto err_exit;
- }
-
- dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
- if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, dev_interface_details, size, &size, NULL))
- usbi_err(ctx, "could not access interface data (actual) for index %u: %s",
- _index, windows_error_str(0));
-
- // [trobinso] lookup the libusb0 symbolic index.
- if (dev_interface_details) {
- HKEY hkey_device_interface = pSetupDiOpenDeviceInterfaceRegKey(*dev_info, &dev_interface_data, 0, KEY_READ);
- if (hkey_device_interface != INVALID_HANDLE_VALUE) {
- DWORD libusb0_symboliclink_index = 0;
- DWORD value_length = sizeof(DWORD);
- DWORD value_type = 0;
- LONG status;
-
- status = pRegQueryValueExW(hkey_device_interface, L"LUsb0", NULL, &value_type,
- (LPBYTE)&libusb0_symboliclink_index, &value_length);
- if (status == ERROR_SUCCESS) {
- if (libusb0_symboliclink_index < 256) {
- // libusb0.sys is connected to this device instance.
- // If the the device interface guid is {F9F3FF14-AE21-48A0-8A25-8011A7A931D9} then it's a filter.
- sprintf(filter_path, "\\\\.\\libusb0-%04u", (unsigned int)libusb0_symboliclink_index);
- usbi_dbg("assigned libusb0 symbolic link %s", filter_path);
- } else {
- // libusb0.sys was connected to this device instance at one time; but not anymore.
- }
- }
- pRegCloseKey(hkey_device_interface);
- }
- }
-
- return dev_interface_details;
-
-err_exit:
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return NULL;
-}
-
-/*
- * Returns the session ID of a device's nth level ancestor
- * If there's no device at the nth level, return 0
- */
-static unsigned long get_ancestor_session_id(DWORD devinst, unsigned level)
-{
- DWORD parent_devinst;
- unsigned long session_id;
- char *sanitized_path;
- char path[MAX_PATH_LENGTH];
- unsigned i;
-
- if (level < 1)
- return 0;
-
- for (i = 0; i < level; i++) {
- if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS)
- return 0;
- devinst = parent_devinst;
- }
-
- if (CM_Get_Device_IDA(devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS)
- return 0;
-
- // TODO: (post hotplug): try without sanitizing
- sanitized_path = sanitize_path(path);
- if (sanitized_path == NULL)
- return 0;
-
- session_id = htab_hash(sanitized_path);
- free(sanitized_path);
- return session_id;
-}
-
-/*
- * Determine which interface the given endpoint address belongs to
- */
-static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, uint8_t ep)
-{
- const struct libusb_interface *intf;
- const struct libusb_interface_descriptor *intf_desc;
- int i, j, k;
-
- for (i = 0; i < conf_desc->bNumInterfaces; i++) {
- intf = &conf_desc->interface[i];
- for (j = 0; j < intf->num_altsetting; j++) {
- intf_desc = &intf->altsetting[j];
- for (k = 0; k < intf_desc->bNumEndpoints; k++) {
- if (intf_desc->endpoint[k].bEndpointAddress == ep) {
- usbi_dbg("found endpoint %02X on interface %d", intf_desc->bInterfaceNumber, i);
- return intf_desc->bInterfaceNumber;
- }
- }
- }
- }
-
- usbi_dbg("endpoint %02X not found on any interface", ep);
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-/*
- * Populate the endpoints addresses of the device_priv interface helper structs
- */
-static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int iface, int altsetting)
-{
- int i, r;
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- struct libusb_config_descriptor *conf_desc;
- const struct libusb_interface_descriptor *if_desc;
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
-
- r = libusb_get_active_config_descriptor(dev_handle->dev, &conf_desc);
- if (r != LIBUSB_SUCCESS) {
- usbi_warn(ctx, "could not read config descriptor: error %d", r);
- return r;
- }
-
- if_desc = &conf_desc->interface[iface].altsetting[altsetting];
- safe_free(priv->usb_interface[iface].endpoint);
-
- if (if_desc->bNumEndpoints == 0) {
- usbi_dbg("no endpoints found for interface %d", iface);
- libusb_free_config_descriptor(conf_desc);
- return LIBUSB_SUCCESS;
- }
-
- priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints);
- if (priv->usb_interface[iface].endpoint == NULL) {
- libusb_free_config_descriptor(conf_desc);
- return LIBUSB_ERROR_NO_MEM;
- }
-
- priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints;
- for (i = 0; i < if_desc->bNumEndpoints; i++) {
- priv->usb_interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress;
- usbi_dbg("(re)assigned endpoint %02X to interface %d", priv->usb_interface[iface].endpoint[i], iface);
- }
- libusb_free_config_descriptor(conf_desc);
-
- // Extra init may be required to configure endpoints
- return priv->apib->configure_endpoints(SUB_API_NOTSET, dev_handle, iface);
-}
-
-// Lookup for a match in the list of API driver names
-// return -1 if not found, driver match number otherwise
-static int get_sub_api(char *driver, int api)
-{
- int i;
- const char sep_str[2] = {LIST_SEPARATOR, 0};
- char *tok, *tmp_str;
- size_t len = strlen(driver);
-
- if (len == 0)
- return SUB_API_NOTSET;
-
- tmp_str = _strdup(driver);
- if (tmp_str == NULL)
- return SUB_API_NOTSET;
-
- tok = strtok(tmp_str, sep_str);
- while (tok != NULL) {
- for (i = 0; i < usb_api_backend[api].nb_driver_names; i++) {
- if (_stricmp(tok, usb_api_backend[api].driver_name_list[i]) == 0) {
- free(tmp_str);
- return i;
- }
- }
- tok = strtok(NULL, sep_str);
- }
-
- free(tmp_str);
- return SUB_API_NOTSET;
-}
-
-/*
- * auto-claiming and auto-release helper functions
- */
-static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type)
-{
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(
- transfer->dev_handle);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- int current_interface = *interface_number;
- int r = LIBUSB_SUCCESS;
-
- switch(api_type) {
- case USB_API_WINUSBX:
- case USB_API_HID:
- break;
- default:
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- usbi_mutex_lock(&autoclaim_lock);
- if (current_interface < 0) { // No serviceable interface was found
- for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) {
- // Must claim an interface of the same API type
- if ((priv->usb_interface[current_interface].apib->id == api_type)
- && (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS)) {
- usbi_dbg("auto-claimed interface %d for control request", current_interface);
- if (handle_priv->autoclaim_count[current_interface] != 0)
- usbi_warn(ctx, "program assertion failed - autoclaim_count was nonzero");
- handle_priv->autoclaim_count[current_interface]++;
- break;
- }
- }
- if (current_interface == USB_MAXINTERFACES) {
- usbi_err(ctx, "could not auto-claim any interface");
- r = LIBUSB_ERROR_NOT_FOUND;
- }
- } else {
- // If we have a valid interface that was autoclaimed, we must increment
- // its autoclaim count so that we can prevent an early release.
- if (handle_priv->autoclaim_count[current_interface] != 0)
- handle_priv->autoclaim_count[current_interface]++;
- }
- usbi_mutex_unlock(&autoclaim_lock);
-
- *interface_number = current_interface;
- return r;
-}
-
-static void auto_release(struct usbi_transfer *itransfer)
-{
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- libusb_device_handle *dev_handle = transfer->dev_handle;
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- int r;
-
- usbi_mutex_lock(&autoclaim_lock);
- if (handle_priv->autoclaim_count[transfer_priv->interface_number] > 0) {
- handle_priv->autoclaim_count[transfer_priv->interface_number]--;
- if (handle_priv->autoclaim_count[transfer_priv->interface_number] == 0) {
- r = libusb_release_interface(dev_handle, transfer_priv->interface_number);
- if (r == LIBUSB_SUCCESS)
- usbi_dbg("auto-released interface %d", transfer_priv->interface_number);
- else
- usbi_dbg("failed to auto-release interface %d (%s)",
- transfer_priv->interface_number, libusb_error_name((enum libusb_error)r));
- }
- }
- usbi_mutex_unlock(&autoclaim_lock);
-}
-
-/* Windows version dtection */
-static BOOL is_x64(void)
-{
- BOOL ret = FALSE;
-
- // Detect if we're running a 32 or 64 bit system
- if (sizeof(uintptr_t) < 8) {
- if (pIsWow64Process != NULL)
- pIsWow64Process(GetCurrentProcess(), &ret);
- } else {
- ret = TRUE;
- }
-
- return ret;
-}
-
-static void get_windows_version(void)
-{
- OSVERSIONINFOEXA vi, vi2;
- const char *arch, *w = NULL;
- unsigned major, minor;
- ULONGLONG major_equal, minor_equal;
- BOOL ws;
-
- memset(&vi, 0, sizeof(vi));
- vi.dwOSVersionInfoSize = sizeof(vi);
- if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
- memset(&vi, 0, sizeof(vi));
- vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
- if (!GetVersionExA((OSVERSIONINFOA *)&vi))
- return;
- }
-
- if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
- if (vi.dwMajorVersion > 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2)) {
- // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version
- // See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
-
- major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
- for (major = vi.dwMajorVersion; major <= 9; major++) {
- memset(&vi2, 0, sizeof(vi2));
- vi2.dwOSVersionInfoSize = sizeof(vi2);
- vi2.dwMajorVersion = major;
- if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal))
- continue;
-
- if (vi.dwMajorVersion < major) {
- vi.dwMajorVersion = major;
- vi.dwMinorVersion = 0;
- }
-
- minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
- for (minor = vi.dwMinorVersion; minor <= 9; minor++) {
- memset(&vi2, 0, sizeof(vi2));
- vi2.dwOSVersionInfoSize = sizeof(vi2);
- vi2.dwMinorVersion = minor;
- if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal))
- continue;
-
- vi.dwMinorVersion = minor;
- break;
- }
-
- break;
- }
- }
-
- if (vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
- ws = (vi.wProductType <= VER_NT_WORKSTATION);
- windows_version = vi.dwMajorVersion << 4 | vi.dwMinorVersion;
- switch (windows_version) {
- case 0x50: w = "2000"; break;
- case 0x51: w = "XP"; break;
- case 0x52: w = "2003"; break;
- case 0x60: w = (ws ? "Vista" : "2008"); break;
- case 0x61: w = (ws ? "7" : "2008_R2"); break;
- case 0x62: w = (ws ? "8" : "2012"); break;
- case 0x63: w = (ws ? "8.1" : "2012_R2"); break;
- case 0x64: w = (ws ? "10" : "2015"); break;
- default:
- if (windows_version < 0x50)
- windows_version = WINDOWS_UNSUPPORTED;
- else
- w = "11 or later";
- break;
- }
- }
- }
-
- arch = is_x64() ? "64-bit" : "32-bit";
-
- if (w == NULL)
- snprintf(windows_version_str, sizeof(windows_version_str), "%s %u.%u %s",
- (vi.dwPlatformId == VER_PLATFORM_WIN32_NT ? "NT" : "??"),
- (unsigned int)vi.dwMajorVersion, (unsigned int)vi.dwMinorVersion, arch);
- else if (vi.wServicePackMinor)
- snprintf(windows_version_str, sizeof(windows_version_str), "%s SP%u.%u %s",
- w, vi.wServicePackMajor, vi.wServicePackMinor, arch);
- else if (vi.wServicePackMajor)
- snprintf(windows_version_str, sizeof(windows_version_str), "%s SP%u %s",
- w, vi.wServicePackMajor, arch);
- else
- snprintf(windows_version_str, sizeof(windows_version_str), "%s %s",
- w, arch);
-}
-
-/*
- * init: libusb backend init function
- *
- * This function enumerates the HCDs (Host Controller Drivers) and populates our private HCD list
- * In our implementation, we equate Windows' "HCD" to libusb's "bus". Note that bus is zero indexed.
- * HCDs are not expected to change after init (might not hold true for hot pluggable USB PCI card?)
- */
-static int windows_init(struct libusb_context *ctx)
-{
- int i, r = LIBUSB_ERROR_OTHER;
- HANDLE semaphore;
- char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
-
- sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
- semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
- if (semaphore == NULL) {
- usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_MEM;
- }
-
- // A successful wait brings our semaphore count to 0 (unsignaled)
- // => any concurent wait stalls until the semaphore's release
- if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
- usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0));
- CloseHandle(semaphore);
- return LIBUSB_ERROR_NO_MEM;
- }
-
- // NB: concurrent usage supposes that init calls are equally balanced with
- // exit calls. If init is called more than exit, we will not exit properly
- if (++concurrent_usage == 0) { // First init?
- get_windows_version();
- usbi_dbg("Windows %s", windows_version_str);
-
- if (windows_version == WINDOWS_UNSUPPORTED) {
- usbi_err(ctx, "This version of Windows is NOT supported");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- goto init_exit;
- }
-
- // We need a lock for proper auto-release
- usbi_mutex_init(&autoclaim_lock);
-
- // Initialize pollable file descriptors
- init_polling();
-
- // Load DLL imports
- if (init_dlls() != LIBUSB_SUCCESS) {
- usbi_err(ctx, "could not resolve DLL functions");
- goto init_exit;
- }
-
- // Initialize the low level APIs (we don't care about errors at this stage)
- for (i = 0; i < USB_API_MAX; i++)
- usb_api_backend[i].init(SUB_API_NOTSET, ctx);
-
- r = windows_common_init(ctx);
- if (r)
- goto init_exit;
- }
- // At this stage, either we went through full init successfully, or didn't need to
- r = LIBUSB_SUCCESS;
-
-init_exit: // Holds semaphore here.
- if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
- for (i = 0; i < USB_API_MAX; i++)
- usb_api_backend[i].exit(SUB_API_NOTSET);
- exit_dlls();
- exit_polling();
- windows_common_exit();
- usbi_mutex_destroy(&autoclaim_lock);
- }
-
- if (r != LIBUSB_SUCCESS)
- --concurrent_usage; // Not expected to call libusb_exit if we failed.
-
- ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
- CloseHandle(semaphore);
- return r;
-}
-
-/*
- * HCD (root) hubs need to have their device descriptor manually populated
- *
- * Note that, like Microsoft does in the device manager, we populate the
- * Vendor and Device ID for HCD hubs with the ones from the PCI HCD device.
- */
-static int force_hcd_device_descriptor(struct libusb_device *dev)
-{
- struct windows_device_priv *parent_priv, *priv = _device_priv(dev);
- struct libusb_context *ctx = DEVICE_CTX(dev);
- int vid, pid;
-
- dev->num_configurations = 1;
- priv->dev_descriptor.bLength = sizeof(USB_DEVICE_DESCRIPTOR);
- priv->dev_descriptor.bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE;
- priv->dev_descriptor.bNumConfigurations = 1;
- priv->active_config = 1;
-
- if (dev->parent_dev == NULL) {
- usbi_err(ctx, "program assertion failed - HCD hub has no parent");
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- parent_priv = _device_priv(dev->parent_dev);
- if (sscanf(parent_priv->path, "\\\\.\\PCI#VEN_%04x&DEV_%04x%*s", &vid, &pid) == 2) {
- priv->dev_descriptor.idVendor = (uint16_t)vid;
- priv->dev_descriptor.idProduct = (uint16_t)pid;
- } else {
- usbi_warn(ctx, "could not infer VID/PID of HCD hub from '%s'", parent_priv->path);
- priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub
- priv->dev_descriptor.idProduct = 1;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-/*
- * fetch and cache all the config descriptors through I/O
- */
-static int cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle, char *device_id)
-{
- DWORD size, ret_size;
- struct libusb_context *ctx = DEVICE_CTX(dev);
- struct windows_device_priv *priv = _device_priv(dev);
- int r;
- uint8_t i;
-
- USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request
- PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request
- PUSB_CONFIGURATION_DESCRIPTOR cd_data = NULL;
-
- if (dev->num_configurations == 0)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- priv->config_descriptor = calloc(dev->num_configurations, sizeof(unsigned char *));
- if (priv->config_descriptor == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- for (i = 0; i < dev->num_configurations; i++)
- priv->config_descriptor[i] = NULL;
-
- for (i = 0, r = LIBUSB_SUCCESS; ; i++) {
- // safe loop: release all dynamic resources
- safe_free(cd_buf_actual);
-
- // safe loop: end of loop condition
- if ((i >= dev->num_configurations) || (r != LIBUSB_SUCCESS))
- break;
-
- size = sizeof(USB_CONFIGURATION_DESCRIPTOR_SHORT);
- memset(&cd_buf_short, 0, size);
-
- cd_buf_short.req.ConnectionIndex = (ULONG)priv->port;
- cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
- cd_buf_short.req.SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
- cd_buf_short.req.SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i;
- cd_buf_short.req.SetupPacket.wIndex = 0;
- cd_buf_short.req.SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST));
-
- // Dummy call to get the required data size. Initial failures are reported as info rather
- // than error as they can occur for non-penalizing situations, such as with some hubs.
- // coverity[tainted_data_argument]
- if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &cd_buf_short, size,
- &cd_buf_short, size, &ret_size, NULL)) {
- usbi_info(ctx, "could not access configuration descriptor (dummy) for '%s': %s", device_id, windows_error_str(0));
- LOOP_BREAK(LIBUSB_ERROR_IO);
- }
-
- if ((ret_size != size) || (cd_buf_short.data.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))) {
- usbi_info(ctx, "unexpected configuration descriptor size (dummy) for '%s'.", device_id);
- LOOP_BREAK(LIBUSB_ERROR_IO);
- }
-
- size = sizeof(USB_DESCRIPTOR_REQUEST) + cd_buf_short.data.wTotalLength;
- cd_buf_actual = calloc(1, size);
- if (cd_buf_actual == NULL) {
- usbi_err(ctx, "could not allocate configuration descriptor buffer for '%s'.", device_id);
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
-
- // Actual call
- cd_buf_actual->ConnectionIndex = (ULONG)priv->port;
- cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
- cd_buf_actual->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
- cd_buf_actual->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i;
- cd_buf_actual->SetupPacket.wIndex = 0;
- cd_buf_actual->SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST));
-
- if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, cd_buf_actual, size,
- cd_buf_actual, size, &ret_size, NULL)) {
- usbi_err(ctx, "could not access configuration descriptor (actual) for '%s': %s", device_id, windows_error_str(0));
- LOOP_BREAK(LIBUSB_ERROR_IO);
- }
-
- cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR *)cd_buf_actual + sizeof(USB_DESCRIPTOR_REQUEST));
-
- if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.data.wTotalLength)) {
- usbi_err(ctx, "unexpected configuration descriptor size (actual) for '%s'.", device_id);
- LOOP_BREAK(LIBUSB_ERROR_IO);
- }
-
- if (cd_data->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE) {
- usbi_err(ctx, "not a configuration descriptor for '%s'", device_id);
- LOOP_BREAK(LIBUSB_ERROR_IO);
- }
-
- usbi_dbg("cached config descriptor %d (bConfigurationValue=%u, %u bytes)",
- i, cd_data->bConfigurationValue, cd_data->wTotalLength);
-
- // Cache the descriptor
- priv->config_descriptor[i] = malloc(cd_data->wTotalLength);
- if (priv->config_descriptor[i] == NULL)
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- memcpy(priv->config_descriptor[i], cd_data, cd_data->wTotalLength);
- }
- return LIBUSB_SUCCESS;
-}
-
-/*
- * Populate a libusb device structure
- */
-static int init_device(struct libusb_device *dev, struct libusb_device *parent_dev,
- uint8_t port_number, char *device_id, DWORD devinst)
-{
- HANDLE handle;
- DWORD size;
- USB_NODE_CONNECTION_INFORMATION_EX conn_info;
- USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2;
- struct windows_device_priv *priv, *parent_priv;
- struct libusb_context *ctx;
- struct libusb_device *tmp_dev;
- unsigned long tmp_id;
- unsigned i;
-
- if ((dev == NULL) || (parent_dev == NULL))
- return LIBUSB_ERROR_NOT_FOUND;
-
- ctx = DEVICE_CTX(dev);
- priv = _device_priv(dev);
- parent_priv = _device_priv(parent_dev);
- if (parent_priv->apib->id != USB_API_HUB) {
- usbi_warn(ctx, "parent for device '%s' is not a hub", device_id);
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- // It is possible for the parent hub not to have been initialized yet
- // If that's the case, lookup the ancestors to set the bus number
- if (parent_dev->bus_number == 0) {
- for (i = 2; ; i++) {
- tmp_id = get_ancestor_session_id(devinst, i);
- if (tmp_id == 0)
- break;
-
- tmp_dev = usbi_get_device_by_session_id(ctx, tmp_id);
- if (tmp_dev == NULL)
- continue;
-
- if (tmp_dev->bus_number != 0) {
- usbi_dbg("got bus number from ancestor #%u", i);
- parent_dev->bus_number = tmp_dev->bus_number;
- libusb_unref_device(tmp_dev);
- break;
- }
-
- libusb_unref_device(tmp_dev);
- }
- }
-
- if (parent_dev->bus_number == 0) {
- usbi_err(ctx, "program assertion failed: unable to find ancestor bus number for '%s'", device_id);
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- dev->bus_number = parent_dev->bus_number;
- priv->port = port_number;
- dev->port_number = port_number;
- priv->depth = parent_priv->depth + 1;
- dev->parent_dev = parent_dev;
-
- // If the device address is already set, we can stop here
- if (dev->device_address != 0)
- return LIBUSB_SUCCESS;
-
- memset(&conn_info, 0, sizeof(conn_info));
- if (priv->depth != 0) { // Not a HCD hub
- handle = CreateFileA(parent_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED, NULL);
- if (handle == INVALID_HANDLE_VALUE) {
- usbi_warn(ctx, "could not open hub %s: %s", parent_priv->path, windows_error_str(0));
- return LIBUSB_ERROR_ACCESS;
- }
-
- size = sizeof(conn_info);
- conn_info.ConnectionIndex = (ULONG)port_number;
- // coverity[tainted_data_argument]
- if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, size,
- &conn_info, size, &size, NULL)) {
- usbi_warn(ctx, "could not get node connection information for device '%s': %s",
- device_id, windows_error_str(0));
- CloseHandle(handle);
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- if (conn_info.ConnectionStatus == NoDeviceConnected) {
- usbi_err(ctx, "device '%s' is no longer connected!", device_id);
- CloseHandle(handle);
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR));
- dev->num_configurations = priv->dev_descriptor.bNumConfigurations;
- priv->active_config = conn_info.CurrentConfigurationValue;
- usbi_dbg("found %u configurations (active conf: %u)", dev->num_configurations, priv->active_config);
-
- // If we can't read the config descriptors, just set the number of confs to zero
- if (cache_config_descriptors(dev, handle, device_id) != LIBUSB_SUCCESS) {
- dev->num_configurations = 0;
- priv->dev_descriptor.bNumConfigurations = 0;
- }
-
- // In their great wisdom, Microsoft decided to BREAK the USB speed report between Windows 7 and Windows 8
- if (windows_version >= WINDOWS_8) {
- memset(&conn_info_v2, 0, sizeof(conn_info_v2));
- size = sizeof(conn_info_v2);
- conn_info_v2.ConnectionIndex = (ULONG)port_number;
- conn_info_v2.Length = size;
- conn_info_v2.SupportedUsbProtocols.Usb300 = 1;
- if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2,
- &conn_info_v2, size, &conn_info_v2, size, &size, NULL)) {
- usbi_warn(ctx, "could not get node connection information (V2) for device '%s': %s",
- device_id, windows_error_str(0));
- } else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedOrHigher) {
- conn_info.Speed = 3;
- }
- }
-
- CloseHandle(handle);
-
- if (conn_info.DeviceAddress > UINT8_MAX)
- usbi_err(ctx, "program assertion failed: device address overflow");
-
- dev->device_address = (uint8_t)conn_info.DeviceAddress + 1;
- if (dev->device_address == 1)
- usbi_err(ctx, "program assertion failed: device address collision with root hub");
-
- switch (conn_info.Speed) {
- case 0: dev->speed = LIBUSB_SPEED_LOW; break;
- case 1: dev->speed = LIBUSB_SPEED_FULL; break;
- case 2: dev->speed = LIBUSB_SPEED_HIGH; break;
- case 3: dev->speed = LIBUSB_SPEED_SUPER; break;
- default:
- usbi_warn(ctx, "Got unknown device speed %u", conn_info.Speed);
- break;
- }
- } else {
- dev->device_address = 1; // root hubs are set to use device number 1
- force_hcd_device_descriptor(dev);
- }
-
- usbi_sanitize_device(dev);
-
- usbi_dbg("(bus: %u, addr: %u, depth: %u, port: %u): '%s'",
- dev->bus_number, dev->device_address, priv->depth, priv->port, device_id);
-
- return LIBUSB_SUCCESS;
-}
-
-// Returns the api type, or 0 if not found/unsupported
-static void get_api_type(struct libusb_context *ctx, HDEVINFO *dev_info,
- SP_DEVINFO_DATA *dev_info_data, int *api, int *sub_api)
-{
- // Precedence for filter drivers vs driver is in the order of this array
- struct driver_lookup lookup[3] = {
- {"\0\0", SPDRP_SERVICE, "driver"},
- {"\0\0", SPDRP_UPPERFILTERS, "upper filter driver"},
- {"\0\0", SPDRP_LOWERFILTERS, "lower filter driver"}
- };
- DWORD size, reg_type;
- unsigned k, l;
- int i, j;
-
- *api = USB_API_UNSUPPORTED;
- *sub_api = SUB_API_NOTSET;
-
- // Check the service & filter names to know the API we should use
- for (k = 0; k < 3; k++) {
- if (pSetupDiGetDeviceRegistryPropertyA(*dev_info, dev_info_data, lookup[k].reg_prop,
- &reg_type, (BYTE *)lookup[k].list, MAX_KEY_LENGTH, &size)) {
- // Turn the REG_SZ SPDRP_SERVICE into REG_MULTI_SZ
- if (lookup[k].reg_prop == SPDRP_SERVICE)
- // our buffers are MAX_KEY_LENGTH + 1 so we can overflow if needed
- lookup[k].list[strlen(lookup[k].list) + 1] = 0;
-
- // MULTI_SZ is a pain to work with. Turn it into something much more manageable
- // NB: none of the driver names we check against contain LIST_SEPARATOR,
- // (currently ';'), so even if an unsuported one does, it's not an issue
- for (l = 0; (lookup[k].list[l] != 0) || (lookup[k].list[l + 1] != 0); l++) {
- if (lookup[k].list[l] == 0)
- lookup[k].list[l] = LIST_SEPARATOR;
- }
- usbi_dbg("%s(s): %s", lookup[k].designation, lookup[k].list);
- } else {
- if (GetLastError() != ERROR_INVALID_DATA)
- usbi_dbg("could not access %s: %s", lookup[k].designation, windows_error_str(0));
- lookup[k].list[0] = 0;
- }
- }
-
- for (i = 1; i < USB_API_MAX; i++) {
- for (k = 0; k < 3; k++) {
- j = get_sub_api(lookup[k].list, i);
- if (j >= 0) {
- usbi_dbg("matched %s name against %s", lookup[k].designation,
- (i != USB_API_WINUSBX) ? usb_api_backend[i].designation : sub_api_name[j]);
- *api = i;
- *sub_api = j;
- return;
- }
- }
- }
-}
-
-static int set_composite_interface(struct libusb_context *ctx, struct libusb_device *dev,
- char *dev_interface_path, char *device_id, int api, int sub_api)
-{
- unsigned i;
- struct windows_device_priv *priv = _device_priv(dev);
- int interface_number;
-
- if (priv->apib->id != USB_API_COMPOSITE) {
- usbi_err(ctx, "program assertion failed: '%s' is not composite", device_id);
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- // Because MI_## are not necessarily in sequential order (some composite
- // devices will have only MI_00 & MI_03 for instance), we retrieve the actual
- // interface number from the path's MI value
- interface_number = 0;
- for (i = 0; device_id[i] != 0; ) {
- if ((device_id[i++] == 'M') && (device_id[i++] == 'I')
- && (device_id[i++] == '_')) {
- interface_number = (device_id[i++] - '0') * 10;
- interface_number += device_id[i] - '0';
- break;
- }
- }
-
- if (device_id[i] == 0)
- usbi_warn(ctx, "failure to read interface number for %s. Using default value %d",
- device_id, interface_number);
-
- if (priv->usb_interface[interface_number].path != NULL) {
- if (api == USB_API_HID) {
- // HID devices can have multiple collections (COL##) for each MI_## interface
- usbi_dbg("interface[%d] already set - ignoring HID collection: %s",
- interface_number, device_id);
- return LIBUSB_ERROR_ACCESS;
- }
- // In other cases, just use the latest data
- safe_free(priv->usb_interface[interface_number].path);
- }
-
- usbi_dbg("interface[%d] = %s", interface_number, dev_interface_path);
- priv->usb_interface[interface_number].path = dev_interface_path;
- priv->usb_interface[interface_number].apib = &usb_api_backend[api];
- priv->usb_interface[interface_number].sub_api = sub_api;
- if ((api == USB_API_HID) && (priv->hid == NULL)) {
- priv->hid = calloc(1, sizeof(struct hid_device_priv));
- if (priv->hid == NULL)
- return LIBUSB_ERROR_NO_MEM;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *dev,
- char *dev_interface_path)
-{
- int i;
- struct windows_device_priv *priv = _device_priv(dev);
-
- if (priv->hid == NULL) {
- usbi_err(ctx, "program assertion failed: parent is not HID");
- return LIBUSB_ERROR_NO_DEVICE;
- } else if (priv->hid->nb_interfaces == USB_MAXINTERFACES) {
- usbi_err(ctx, "program assertion failed: max USB interfaces reached for HID device");
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- for (i = 0; i < priv->hid->nb_interfaces; i++) {
- if ((priv->usb_interface[i].path != NULL) && strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) {
- usbi_dbg("interface[%d] already set to %s", i, dev_interface_path);
- return LIBUSB_ERROR_ACCESS;
- }
- }
-
- priv->usb_interface[priv->hid->nb_interfaces].path = dev_interface_path;
- priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID];
- usbi_dbg("interface[%u] = %s", priv->hid->nb_interfaces, dev_interface_path);
- priv->hid->nb_interfaces++;
- return LIBUSB_SUCCESS;
-}
-
-/*
- * get_device_list: libusb backend device enumeration function
- */
-static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
-{
- struct discovered_devs *discdevs;
- HDEVINFO dev_info = { 0 };
- const char *usb_class[] = {"USB", "NUSB3", "IUSB3", "IARUSB3"};
- SP_DEVINFO_DATA dev_info_data = { 0 };
- SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL;
- GUID hid_guid;
-#define MAX_ENUM_GUIDS 64
- const GUID *guid[MAX_ENUM_GUIDS];
-#define HCD_PASS 0
-#define HUB_PASS 1
-#define GEN_PASS 2
-#define DEV_PASS 3
-#define HID_PASS 4
- int r = LIBUSB_SUCCESS;
- int api, sub_api;
- size_t class_index = 0;
- unsigned int nb_guids, pass, i, j, ancestor;
- char path[MAX_PATH_LENGTH];
- char strbuf[MAX_PATH_LENGTH];
- struct libusb_device *dev, *parent_dev;
- struct windows_device_priv *priv, *parent_priv;
- char *dev_interface_path = NULL;
- char *dev_id_path = NULL;
- unsigned long session_id;
- DWORD size, reg_type, port_nr, install_state;
- HKEY key;
- WCHAR guid_string_w[MAX_GUID_STRING_LENGTH];
- GUID *if_guid;
- LONG s;
- // Keep a list of newly allocated devs to unref
- libusb_device **unref_list, **new_unref_list;
- unsigned int unref_size = 64;
- unsigned int unref_cur = 0;
-
- // PASS 1 : (re)enumerate HCDs (allows for HCD hotplug)
- // PASS 2 : (re)enumerate HUBS
- // PASS 3 : (re)enumerate generic USB devices (including driverless)
- // and list additional USB device interface GUIDs to explore
- // PASS 4 : (re)enumerate master USB devices that have a device interface
- // PASS 5+: (re)enumerate device interfaced GUIDs (including HID) and
- // set the device interfaces.
-
- // Init the GUID table
- guid[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER;
- guid[HUB_PASS] = &GUID_DEVINTERFACE_USB_HUB;
- guid[GEN_PASS] = NULL;
- guid[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE;
- HidD_GetHidGuid(&hid_guid);
- guid[HID_PASS] = &hid_guid;
- nb_guids = HID_PASS + 1;
-
- unref_list = calloc(unref_size, sizeof(libusb_device *));
- if (unref_list == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- for (pass = 0; ((pass < nb_guids) && (r == LIBUSB_SUCCESS)); pass++) {
-//#define ENUM_DEBUG
-#if defined(ENABLE_LOGGING) && defined(ENUM_DEBUG)
- const char *passname[] = { "HCD", "HUB", "GEN", "DEV", "HID", "EXT" };
- usbi_dbg("#### PROCESSING %ss %s", passname[(pass <= HID_PASS) ? pass : (HID_PASS + 1)],
- (pass != GEN_PASS) ? guid_to_string(guid[pass]) : "");
-#endif
- for (i = 0; ; i++) {
- // safe loop: free up any (unprotected) dynamic resource
- // NB: this is always executed before breaking the loop
- safe_free(dev_interface_details);
- safe_free(dev_interface_path);
- safe_free(dev_id_path);
- priv = parent_priv = NULL;
- dev = parent_dev = NULL;
-
- // Safe loop: end of loop conditions
- if (r != LIBUSB_SUCCESS)
- break;
-
- if ((pass == HCD_PASS) && (i == UINT8_MAX)) {
- usbi_warn(ctx, "program assertion failed - found more than %d buses, skipping the rest.", UINT8_MAX);
- break;
- }
-
- if (pass != GEN_PASS) {
- // Except for GEN, all passes deal with device interfaces
- dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, guid[pass], i);
- if (dev_interface_details == NULL)
- break;
-
- dev_interface_path = sanitize_path(dev_interface_details->DevicePath);
- if (dev_interface_path == NULL) {
- usbi_warn(ctx, "could not sanitize device interface path for '%s'", dev_interface_details->DevicePath);
- continue;
- }
- } else {
- // Workaround for a Nec/Renesas USB 3.0 driver bug where root hubs are
- // being listed under the "NUSB3" PnP Symbolic Name rather than "USB".
- // The Intel USB 3.0 driver behaves similar, but uses "IUSB3"
- // The Intel Alpine Ridge USB 3.1 driver uses "IARUSB3"
- for (; class_index < ARRAYSIZE(usb_class); class_index++) {
- if (get_devinfo_data(ctx, &dev_info, &dev_info_data, usb_class[class_index], i))
- break;
- i = 0;
- }
- if (class_index >= ARRAYSIZE(usb_class))
- break;
- }
-
- // Read the Device ID path. This is what we'll use as UID
- // Note that if the device is plugged in a different port or hub, the Device ID changes
- if (CM_Get_Device_IDA(dev_info_data.DevInst, path, sizeof(path), 0) != CR_SUCCESS) {
- usbi_warn(ctx, "could not read the device id path for devinst %X, skipping",
- (unsigned int)dev_info_data.DevInst);
- continue;
- }
-
- dev_id_path = sanitize_path(path);
- if (dev_id_path == NULL) {
- usbi_warn(ctx, "could not sanitize device id path for devinst %X, skipping",
- (unsigned int)dev_info_data.DevInst);
- continue;
- }
-#ifdef ENUM_DEBUG
- usbi_dbg("PRO: %s", dev_id_path);
-#endif
-
- // The SPDRP_ADDRESS for USB devices is the device port number on the hub
- port_nr = 0;
- if ((pass >= HUB_PASS) && (pass <= GEN_PASS)) {
- if ((!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ADDRESS,
- &reg_type, (BYTE *)&port_nr, 4, &size)) || (size != 4)) {
- usbi_warn(ctx, "could not retrieve port number for device '%s', skipping: %s",
- dev_id_path, windows_error_str(0));
- continue;
- }
- }
-
- // Set API to use or get additional data from generic pass
- api = USB_API_UNSUPPORTED;
- sub_api = SUB_API_NOTSET;
- switch (pass) {
- case HCD_PASS:
- break;
- case GEN_PASS:
- // We use the GEN pass to detect driverless devices...
- size = sizeof(strbuf);
- if (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_DRIVER,
- &reg_type, (BYTE *)strbuf, size, &size)) {
- usbi_info(ctx, "The following device has no driver: '%s'", dev_id_path);
- usbi_info(ctx, "libusb will not be able to access it.");
- }
- // ...and to add the additional device interface GUIDs
- key = pSetupDiOpenDevRegKey(dev_info, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
- if (key != INVALID_HANDLE_VALUE) {
- size = sizeof(guid_string_w);
- s = pRegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, &reg_type,
- (BYTE *)guid_string_w, &size);
- pRegCloseKey(key);
- if (s == ERROR_SUCCESS) {
- if (nb_guids >= MAX_ENUM_GUIDS) {
- // If this assert is ever reported, grow a GUID table dynamically
- usbi_err(ctx, "program assertion failed: too many GUIDs");
- LOOP_BREAK(LIBUSB_ERROR_OVERFLOW);
- }
- if_guid = calloc(1, sizeof(GUID));
- if (if_guid == NULL) {
- usbi_err(ctx, "could not calloc for if_guid: not enough memory");
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
- pCLSIDFromString(guid_string_w, if_guid);
- guid[nb_guids++] = if_guid;
- usbi_dbg("extra GUID: %s", guid_to_string(if_guid));
- }
- }
- break;
- case HID_PASS:
- api = USB_API_HID;
- break;
- default:
- // Get the API type (after checking that the driver installation is OK)
- if ((!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_INSTALL_STATE,
- &reg_type, (BYTE *)&install_state, 4, &size)) || (size != 4)) {
- usbi_warn(ctx, "could not detect installation state of driver for '%s': %s",
- dev_id_path, windows_error_str(0));
- } else if (install_state != 0) {
- usbi_warn(ctx, "driver for device '%s' is reporting an issue (code: %u) - skipping",
- dev_id_path, (unsigned int)install_state);
- continue;
- }
- get_api_type(ctx, &dev_info, &dev_info_data, &api, &sub_api);
- break;
- }
-
- // Find parent device (for the passes that need it)
- switch (pass) {
- case HCD_PASS:
- case DEV_PASS:
- case HUB_PASS:
- break;
- default:
- // Go through the ancestors until we see a face we recognize
- parent_dev = NULL;
- for (ancestor = 1; parent_dev == NULL; ancestor++) {
- session_id = get_ancestor_session_id(dev_info_data.DevInst, ancestor);
- if (session_id == 0)
- break;
-
- parent_dev = usbi_get_device_by_session_id(ctx, session_id);
- }
-
- if (parent_dev == NULL) {
- usbi_dbg("unlisted ancestor for '%s' (non USB HID, newly connected, etc.) - ignoring", dev_id_path);
- continue;
- }
-
- parent_priv = _device_priv(parent_dev);
- // virtual USB devices are also listed during GEN - don't process these yet
- if ((pass == GEN_PASS) && (parent_priv->apib->id != USB_API_HUB)) {
- libusb_unref_device(parent_dev);
- continue;
- }
-
- break;
- }
-
- // Create new or match existing device, using the (hashed) device_id as session id
- if (pass <= DEV_PASS) { // For subsequent passes, we'll lookup the parent
- // These are the passes that create "new" devices
- session_id = htab_hash(dev_id_path);
- dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev == NULL) {
- if (pass == DEV_PASS) {
- // This can occur if the OS only reports a newly plugged device after we started enum
- usbi_warn(ctx, "'%s' was only detected in late pass (newly connected device?)"
- " - ignoring", dev_id_path);
- continue;
- }
-
- usbi_dbg("allocating new device for session [%lX]", session_id);
- dev = usbi_alloc_device(ctx, session_id);
- if (dev == NULL)
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
-
- priv = windows_device_priv_init(dev);
- } else {
- usbi_dbg("found existing device for session [%lX] (%u.%u)",
- session_id, dev->bus_number, dev->device_address);
-
- priv = _device_priv(dev);
- if ((parent_dev != NULL) && (dev->parent_dev != NULL)) {
- if (dev->parent_dev != parent_dev) {
- // It is possible for the actual parent device to not have existed at the
- // time of enumeration, so the currently assigned parent may in fact be a
- // grandparent. If the devices differ, we assume the "new" parent device
- // is in fact closer to the device.
- usbi_dbg("updating parent device [session %lX -> %lX]",
- dev->parent_dev->session_data, parent_dev->session_data);
- libusb_unref_device(dev->parent_dev);
- dev->parent_dev = parent_dev;
- } else {
- // We hold a reference to parent_dev instance, but this device already
- // has a parent_dev reference (only one per child)
- libusb_unref_device(parent_dev);
- }
- }
- }
-
- // Keep track of devices that need unref
- unref_list[unref_cur++] = dev;
- if (unref_cur >= unref_size) {
- unref_size += 64;
- new_unref_list = usbi_reallocf(unref_list, unref_size * sizeof(libusb_device *));
- if (new_unref_list == NULL) {
- usbi_err(ctx, "could not realloc list for unref - aborting.");
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- } else {
- unref_list = new_unref_list;
- }
- }
- }
-
- // Setup device
- switch (pass) {
- case HCD_PASS:
- // If the hcd has already been setup, don't do it again
- if (priv->path != NULL)
- break;
- dev->bus_number = (uint8_t)(i + 1); // bus 0 is reserved for disconnected
- dev->device_address = 0;
- dev->num_configurations = 0;
- priv->apib = &usb_api_backend[USB_API_HUB];
- priv->sub_api = SUB_API_NOTSET;
- priv->depth = UINT8_MAX; // Overflow to 0 for HCD Hubs
- priv->path = dev_interface_path;
- dev_interface_path = NULL;
- break;
- case HUB_PASS:
- case DEV_PASS:
- // If the device has already been setup, don't do it again
- if (priv->path != NULL)
- break;
- // Take care of API initialization
- priv->path = dev_interface_path;
- dev_interface_path = NULL;
- priv->apib = &usb_api_backend[api];
- priv->sub_api = sub_api;
- switch(api) {
- case USB_API_COMPOSITE:
- case USB_API_HUB:
- break;
- case USB_API_HID:
- priv->hid = calloc(1, sizeof(struct hid_device_priv));
- if (priv->hid == NULL)
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
-
- priv->hid->nb_interfaces = 0;
- break;
- default:
- // For other devices, the first interface is the same as the device
- priv->usb_interface[0].path = _strdup(priv->path);
- if (priv->usb_interface[0].path == NULL)
- usbi_warn(ctx, "could not duplicate interface path '%s'", priv->path);
- // The following is needed if we want API calls to work for both simple
- // and composite devices.
- for (j = 0; j < USB_MAXINTERFACES; j++)
- priv->usb_interface[j].apib = &usb_api_backend[api];
-
- break;
- }
- break;
- case GEN_PASS:
- r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_id_path, dev_info_data.DevInst);
- if (r == LIBUSB_SUCCESS) {
- // Append device to the list of discovered devices
- discdevs = discovered_devs_append(*_discdevs, dev);
- if (!discdevs)
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
-
- *_discdevs = discdevs;
- } else if (r == LIBUSB_ERROR_NO_DEVICE) {
- // This can occur if the device was disconnected but Windows hasn't
- // refreshed its enumeration yet - in that case, we ignore the device
- r = LIBUSB_SUCCESS;
- }
- break;
- default: // HID_PASS and later
- if (parent_priv->apib->id == USB_API_HID || parent_priv->apib->id == USB_API_COMPOSITE) {
- if (parent_priv->apib->id == USB_API_HID) {
- usbi_dbg("setting HID interface for [%lX]:", parent_dev->session_data);
- r = set_hid_interface(ctx, parent_dev, dev_interface_path);
- } else {
- usbi_dbg("setting composite interface for [%lX]:", parent_dev->session_data);
- r = set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id_path, api, sub_api);
- }
- switch (r) {
- case LIBUSB_SUCCESS:
- dev_interface_path = NULL;
- break;
- case LIBUSB_ERROR_ACCESS:
- // interface has already been set => make sure dev_interface_path is freed then
- r = LIBUSB_SUCCESS;
- break;
- default:
- LOOP_BREAK(r);
- break;
- }
- }
- libusb_unref_device(parent_dev);
- break;
- }
- }
- }
-
- // Free any additional GUIDs
- for (pass = HID_PASS + 1; pass < nb_guids; pass++)
- free((void *)guid[pass]);
-
- // Unref newly allocated devs
- for (i = 0; i < unref_cur; i++)
- libusb_unref_device(unref_list[i]);
- free(unref_list);
-
- return r;
-}
-
-/*
- * exit: libusb backend deinitialization function
- */
-static void windows_exit(void)
-{
- int i;
- HANDLE semaphore;
- char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
-
- sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
- semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
- if (semaphore == NULL)
- return;
-
- // A successful wait brings our semaphore count to 0 (unsignaled)
- // => any concurent wait stalls until the semaphore release
- if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
- CloseHandle(semaphore);
- return;
- }
-
- // Only works if exits and inits are balanced exactly
- if (--concurrent_usage < 0) { // Last exit
- for (i = 0; i < USB_API_MAX; i++)
- usb_api_backend[i].exit(SUB_API_NOTSET);
- exit_dlls();
- exit_polling();
- windows_common_exit();
- usbi_mutex_destroy(&autoclaim_lock);
- }
-
- ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
- CloseHandle(semaphore);
-}
-
-static int windows_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian)
-{
- struct windows_device_priv *priv = _device_priv(dev);
-
- memcpy(buffer, &priv->dev_descriptor, DEVICE_DESC_LENGTH);
- *host_endian = 0;
-
- return LIBUSB_SUCCESS;
-}
-
-static int windows_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
-{
- struct windows_device_priv *priv = _device_priv(dev);
- PUSB_CONFIGURATION_DESCRIPTOR config_header;
- size_t size;
-
- // config index is zero based
- if (config_index >= dev->num_configurations)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- if ((priv->config_descriptor == NULL) || (priv->config_descriptor[config_index] == NULL))
- return LIBUSB_ERROR_NOT_FOUND;
-
- config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptor[config_index];
-
- size = MIN(config_header->wTotalLength, len);
- memcpy(buffer, priv->config_descriptor[config_index], size);
- *host_endian = 0;
-
- return (int)size;
-}
-
-static int windows_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
- unsigned char **buffer, int *host_endian)
-{
- struct windows_device_priv *priv = _device_priv(dev);
- PUSB_CONFIGURATION_DESCRIPTOR config_header;
- uint8_t index;
-
- *buffer = NULL;
- *host_endian = 0;
-
- if (priv->config_descriptor == NULL)
- return LIBUSB_ERROR_NOT_FOUND;
-
- for (index = 0; index < dev->num_configurations; index++) {
- config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptor[index];
- if (config_header->bConfigurationValue == bConfigurationValue) {
- *buffer = priv->config_descriptor[index];
- return (int)config_header->wTotalLength;
- }
- }
-
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-/*
- * return the cached copy of the active config descriptor
- */
-static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian)
-{
- struct windows_device_priv *priv = _device_priv(dev);
- unsigned char *config_desc;
- int r;
-
- if (priv->active_config == 0)
- return LIBUSB_ERROR_NOT_FOUND;
-
- r = windows_get_config_descriptor_by_value(dev, priv->active_config, &config_desc, host_endian);
- if (r < 0)
- return r;
-
- len = MIN((size_t)r, len);
- memcpy(buffer, config_desc, len);
- return (int)len;
-}
-
-static int windows_open(struct libusb_device_handle *dev_handle)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
-
- if (priv->apib == NULL) {
- usbi_err(ctx, "program assertion failed - device is not initialized");
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return priv->apib->open(SUB_API_NOTSET, dev_handle);
-}
-
-static void windows_close(struct libusb_device_handle *dev_handle)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
-
- priv->apib->close(SUB_API_NOTSET, dev_handle);
-}
-
-static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
-
- if (priv->active_config == 0) {
- *config = 0;
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- *config = priv->active_config;
- return LIBUSB_SUCCESS;
-}
-
-/*
- * from http://msdn.microsoft.com/en-us/library/ms793522.aspx: "The port driver
- * does not currently expose a service that allows higher-level drivers to set
- * the configuration."
- */
-static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- int r = LIBUSB_SUCCESS;
-
- if (config >= USB_MAXCONFIG)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_OUT |
- LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
- LIBUSB_REQUEST_SET_CONFIGURATION, (uint16_t)config,
- 0, NULL, 0, 1000);
-
- if (r == LIBUSB_SUCCESS)
- priv->active_config = (uint8_t)config;
-
- return r;
-}
-
-static int windows_claim_interface(struct libusb_device_handle *dev_handle, int iface)
-{
- int r = LIBUSB_SUCCESS;
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
-
- safe_free(priv->usb_interface[iface].endpoint);
- priv->usb_interface[iface].nb_endpoints = 0;
-
- r = priv->apib->claim_interface(SUB_API_NOTSET, dev_handle, iface);
-
- if (r == LIBUSB_SUCCESS)
- r = windows_assign_endpoints(dev_handle, iface, 0);
-
- return r;
-}
-
-static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
-{
- int r = LIBUSB_SUCCESS;
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
-
- safe_free(priv->usb_interface[iface].endpoint);
- priv->usb_interface[iface].nb_endpoints = 0;
-
- r = priv->apib->set_interface_altsetting(SUB_API_NOTSET, dev_handle, iface, altsetting);
-
- if (r == LIBUSB_SUCCESS)
- r = windows_assign_endpoints(dev_handle, iface, altsetting);
-
- return r;
-}
-
-static int windows_release_interface(struct libusb_device_handle *dev_handle, int iface)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
-
- return priv->apib->release_interface(SUB_API_NOTSET, dev_handle, iface);
-}
-
-static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- return priv->apib->clear_halt(SUB_API_NOTSET, dev_handle, endpoint);
-}
-
-static int windows_reset_device(struct libusb_device_handle *dev_handle)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- return priv->apib->reset_device(SUB_API_NOTSET, dev_handle);
-}
-
-// The 3 functions below are unlikely to ever get supported on Windows
-static int windows_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int windows_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int windows_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static void windows_destroy_device(struct libusb_device *dev)
-{
- windows_device_priv_release(dev);
-}
-
-void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
-{
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
-
- usbi_free_fd(&transfer_priv->pollable_fd);
- safe_free(transfer_priv->hid_buffer);
- // When auto claim is in use, attempt to release the auto-claimed interface
- auto_release(itransfer);
-}
-
-static int submit_bulk_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- int r;
-
- r = priv->apib->submit_bulk_transfer(SUB_API_NOTSET, itransfer);
- if (r != LIBUSB_SUCCESS)
- return r;
-
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
- (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
-
- return LIBUSB_SUCCESS;
-}
-
-static int submit_iso_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- int r;
-
- r = priv->apib->submit_iso_transfer(SUB_API_NOTSET, itransfer);
- if (r != LIBUSB_SUCCESS)
- return r;
-
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
- (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
-
- return LIBUSB_SUCCESS;
-}
-
-static int submit_control_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- int r;
-
- r = priv->apib->submit_control_transfer(SUB_API_NOTSET, itransfer);
- if (r != LIBUSB_SUCCESS)
- return r;
-
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
-
- return LIBUSB_SUCCESS;
-}
-
-static int windows_submit_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- return submit_control_transfer(itransfer);
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
- return LIBUSB_ERROR_NOT_SUPPORTED;
- return submit_bulk_transfer(itransfer);
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- return submit_iso_transfer(itransfer);
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- return LIBUSB_ERROR_NOT_SUPPORTED;
- default:
- usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-}
-
-static int windows_abort_control(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
-
- return priv->apib->abort_control(SUB_API_NOTSET, itransfer);
-}
-
-static int windows_abort_transfers(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
-
- return priv->apib->abort_transfers(SUB_API_NOTSET, itransfer);
-}
-
-static int windows_cancel_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- return windows_abort_control(itransfer);
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- return windows_abort_transfers(itransfer);
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- return LIBUSB_ERROR_NOT_SUPPORTED;
- default:
- usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-}
-
-int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size);
-}
-
-struct winfd *windows_get_fd(struct usbi_transfer *transfer)
-{
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(transfer);
- return &transfer_priv->pollable_fd;
-}
-
-void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size)
-{
- if (HasOverlappedIoCompletedSync(pollable_fd->overlapped)) {
- *io_result = NO_ERROR;
- *io_size = (DWORD)pollable_fd->overlapped->InternalHigh;
- } else if (GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) {
- // Regular async overlapped
- *io_result = NO_ERROR;
- } else {
- *io_result = GetLastError();
- }
-}
-
-// NB: MSVC6 does not support named initializers.
-const struct usbi_os_backend windows_backend = {
- "Windows",
- USBI_CAP_HAS_HID_ACCESS,
- windows_init,
- windows_exit,
-
- windows_get_device_list,
- NULL, /* hotplug_poll */
- windows_open,
- windows_close,
-
- windows_get_device_descriptor,
- windows_get_active_config_descriptor,
- windows_get_config_descriptor,
- windows_get_config_descriptor_by_value,
-
- windows_get_configuration,
- windows_set_configuration,
- windows_claim_interface,
- windows_release_interface,
-
- windows_set_interface_altsetting,
- windows_clear_halt,
- windows_reset_device,
-
- NULL, /* alloc_streams */
- NULL, /* free_streams */
-
- NULL, /* dev_mem_alloc */
- NULL, /* dev_mem_free */
-
- windows_kernel_driver_active,
- windows_detach_kernel_driver,
- windows_attach_kernel_driver,
-
- windows_destroy_device,
-
- windows_submit_transfer,
- windows_cancel_transfer,
- windows_clear_transfer_priv,
-
- windows_handle_events,
- NULL,
-
- windows_clock_gettime,
-#if defined(USBI_TIMERFD_AVAILABLE)
- NULL,
-#endif
- sizeof(struct windows_device_priv),
- sizeof(struct windows_device_handle_priv),
- sizeof(struct windows_transfer_priv),
-};
-
-
-/*
- * USB API backends
- */
-static int unsupported_init(int sub_api, struct libusb_context *ctx)
-{
- return LIBUSB_SUCCESS;
-}
-
-static int unsupported_exit(int sub_api)
-{
- return LIBUSB_SUCCESS;
-}
-
-static int unsupported_open(int sub_api, struct libusb_device_handle *dev_handle)
-{
- PRINT_UNSUPPORTED_API(open);
-}
-
-static void unsupported_close(int sub_api, struct libusb_device_handle *dev_handle)
-{
- usbi_dbg("unsupported API call for 'close'");
-}
-
-static int unsupported_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- PRINT_UNSUPPORTED_API(configure_endpoints);
-}
-
-static int unsupported_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- PRINT_UNSUPPORTED_API(claim_interface);
-}
-
-static int unsupported_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting)
-{
- PRINT_UNSUPPORTED_API(set_interface_altsetting);
-}
-
-static int unsupported_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- PRINT_UNSUPPORTED_API(release_interface);
-}
-
-static int unsupported_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- PRINT_UNSUPPORTED_API(clear_halt);
-}
-
-static int unsupported_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
-{
- PRINT_UNSUPPORTED_API(reset_device);
-}
-
-static int unsupported_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- PRINT_UNSUPPORTED_API(submit_bulk_transfer);
-}
-
-static int unsupported_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- PRINT_UNSUPPORTED_API(submit_iso_transfer);
-}
-
-static int unsupported_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- PRINT_UNSUPPORTED_API(submit_control_transfer);
-}
-
-static int unsupported_abort_control(int sub_api, struct usbi_transfer *itransfer)
-{
- PRINT_UNSUPPORTED_API(abort_control);
-}
-
-static int unsupported_abort_transfers(int sub_api, struct usbi_transfer *itransfer)
-{
- PRINT_UNSUPPORTED_API(abort_transfers);
-}
-
-static int unsupported_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size)
-{
- PRINT_UNSUPPORTED_API(copy_transfer_data);
-}
-
-static int common_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- return LIBUSB_SUCCESS;
-}
-
-// These names must be uppercase
-static const char *hub_driver_names[] = {"USBHUB", "USBHUB3", "USB3HUB", "NUSB3HUB", "RUSB3HUB", "FLXHCIH", "TIHUB3", "ETRONHUB3", "VIAHUB3", "ASMTHUB3", "IUSB3HUB", "VUSB3HUB", "AMDHUB30", "VHHUB", "AUSB3HUB"};
-static const char *composite_driver_names[] = {"USBCCGP"};
-static const char *winusbx_driver_names[] = WINUSBX_DRV_NAMES;
-static const char *hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"};
-const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
- {
- USB_API_UNSUPPORTED,
- "Unsupported API",
- NULL,
- 0,
- unsupported_init,
- unsupported_exit,
- unsupported_open,
- unsupported_close,
- unsupported_configure_endpoints,
- unsupported_claim_interface,
- unsupported_set_interface_altsetting,
- unsupported_release_interface,
- unsupported_clear_halt,
- unsupported_reset_device,
- unsupported_submit_bulk_transfer,
- unsupported_submit_iso_transfer,
- unsupported_submit_control_transfer,
- unsupported_abort_control,
- unsupported_abort_transfers,
- unsupported_copy_transfer_data,
- },
- {
- USB_API_HUB,
- "HUB API",
- hub_driver_names,
- ARRAYSIZE(hub_driver_names),
- unsupported_init,
- unsupported_exit,
- unsupported_open,
- unsupported_close,
- unsupported_configure_endpoints,
- unsupported_claim_interface,
- unsupported_set_interface_altsetting,
- unsupported_release_interface,
- unsupported_clear_halt,
- unsupported_reset_device,
- unsupported_submit_bulk_transfer,
- unsupported_submit_iso_transfer,
- unsupported_submit_control_transfer,
- unsupported_abort_control,
- unsupported_abort_transfers,
- unsupported_copy_transfer_data,
- },
- {
- USB_API_COMPOSITE,
- "Composite API",
- composite_driver_names,
- ARRAYSIZE(composite_driver_names),
- composite_init,
- composite_exit,
- composite_open,
- composite_close,
- common_configure_endpoints,
- composite_claim_interface,
- composite_set_interface_altsetting,
- composite_release_interface,
- composite_clear_halt,
- composite_reset_device,
- composite_submit_bulk_transfer,
- composite_submit_iso_transfer,
- composite_submit_control_transfer,
- composite_abort_control,
- composite_abort_transfers,
- composite_copy_transfer_data,
- },
- {
- USB_API_WINUSBX,
- "WinUSB-like APIs",
- winusbx_driver_names,
- ARRAYSIZE(winusbx_driver_names),
- winusbx_init,
- winusbx_exit,
- winusbx_open,
- winusbx_close,
- winusbx_configure_endpoints,
- winusbx_claim_interface,
- winusbx_set_interface_altsetting,
- winusbx_release_interface,
- winusbx_clear_halt,
- winusbx_reset_device,
- winusbx_submit_bulk_transfer,
- unsupported_submit_iso_transfer,
- winusbx_submit_control_transfer,
- winusbx_abort_control,
- winusbx_abort_transfers,
- winusbx_copy_transfer_data,
- },
- {
- USB_API_HID,
- "HID API",
- hid_driver_names,
- ARRAYSIZE(hid_driver_names),
- hid_init,
- hid_exit,
- hid_open,
- hid_close,
- common_configure_endpoints,
- hid_claim_interface,
- hid_set_interface_altsetting,
- hid_release_interface,
- hid_clear_halt,
- hid_reset_device,
- hid_submit_bulk_transfer,
- unsupported_submit_iso_transfer,
- hid_submit_control_transfer,
- hid_abort_transfers,
- hid_abort_transfers,
- hid_copy_transfer_data,
- },
-};
-
-
-/*
- * WinUSB-like (WinUSB, libusb0/libusbK through libusbk DLL) API functions
- */
-#define WinUSBX_Set(fn) \
- do { \
- if (native_winusb) \
- WinUSBX[i].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn); \
- else \
- pLibK_GetProcAddress((PVOID *)&WinUSBX[i].fn, i, KUSB_FNID_##fn); \
- } while (0)
-
-static int winusbx_init(int sub_api, struct libusb_context *ctx)
-{
- HMODULE h;
- bool native_winusb;
- int i;
- KLIB_VERSION LibK_Version;
- LibK_GetProcAddress_t pLibK_GetProcAddress = NULL;
- LibK_GetVersion_t pLibK_GetVersion;
-
- h = LoadLibraryA("libusbK");
-
- if (h == NULL) {
- usbi_info(ctx, "libusbK DLL is not available, will use native WinUSB");
- h = LoadLibraryA("WinUSB");
-
- if (h == NULL) {
- usbi_warn(ctx, "WinUSB DLL is not available either, "
- "you will not be able to access devices outside of enumeration");
- return LIBUSB_ERROR_NOT_FOUND;
- }
- } else {
- usbi_dbg("using libusbK DLL for universal access");
- pLibK_GetVersion = (LibK_GetVersion_t)GetProcAddress(h, "LibK_GetVersion");
- if (pLibK_GetVersion != NULL) {
- pLibK_GetVersion(&LibK_Version);
- usbi_dbg("libusbK version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor,
- LibK_Version.Micro, LibK_Version.Nano);
- }
- pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(h, "LibK_GetProcAddress");
- if (pLibK_GetProcAddress == NULL) {
- usbi_err(ctx, "LibK_GetProcAddress() not found in libusbK DLL");
- FreeLibrary(h);
- return LIBUSB_ERROR_NOT_FOUND;
- }
- }
-
- native_winusb = (pLibK_GetProcAddress == NULL);
- for (i = SUB_API_LIBUSBK; i < SUB_API_MAX; i++) {
- WinUSBX_Set(AbortPipe);
- WinUSBX_Set(ControlTransfer);
- WinUSBX_Set(FlushPipe);
- WinUSBX_Set(Free);
- WinUSBX_Set(GetAssociatedInterface);
- WinUSBX_Set(GetCurrentAlternateSetting);
- WinUSBX_Set(GetDescriptor);
- WinUSBX_Set(GetOverlappedResult);
- WinUSBX_Set(GetPipePolicy);
- WinUSBX_Set(GetPowerPolicy);
- WinUSBX_Set(Initialize);
- WinUSBX_Set(QueryDeviceInformation);
- WinUSBX_Set(QueryInterfaceSettings);
- WinUSBX_Set(QueryPipe);
- WinUSBX_Set(ReadPipe);
- WinUSBX_Set(ResetPipe);
- WinUSBX_Set(SetCurrentAlternateSetting);
- WinUSBX_Set(SetPipePolicy);
- WinUSBX_Set(SetPowerPolicy);
- WinUSBX_Set(WritePipe);
- if (!native_winusb)
- WinUSBX_Set(ResetDevice);
-
- if (WinUSBX[i].Initialize != NULL) {
- WinUSBX[i].initialized = true;
- usbi_dbg("initalized sub API %s", sub_api_name[i]);
- } else {
- usbi_warn(ctx, "Failed to initalize sub API %s", sub_api_name[i]);
- WinUSBX[i].initialized = false;
- }
- }
-
- WinUSBX_handle = h;
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_exit(int sub_api)
-{
- if (WinUSBX_handle != NULL) {
- FreeLibrary(WinUSBX_handle);
- WinUSBX_handle = NULL;
-
- /* Reset the WinUSBX API structures */
- memset(&WinUSBX, 0, sizeof(WinUSBX));
- }
-
- return LIBUSB_SUCCESS;
-}
-
-// NB: open and close must ensure that they only handle interface of
-// the right API type, as these functions can be called wholesale from
-// composite_open(), with interfaces belonging to different APIs
-static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
-
- HANDLE file_handle;
- int i;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- // WinUSB requires a separate handle for each interface
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if ((priv->usb_interface[i].path != NULL)
- && (priv->usb_interface[i].apib->id == USB_API_WINUSBX)) {
- file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
- if (file_handle == INVALID_HANDLE_VALUE) {
- usbi_err(ctx, "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0));
- switch(GetLastError()) {
- case ERROR_FILE_NOT_FOUND: // The device was disconnected
- return LIBUSB_ERROR_NO_DEVICE;
- case ERROR_ACCESS_DENIED:
- return LIBUSB_ERROR_ACCESS;
- default:
- return LIBUSB_ERROR_IO;
- }
- }
- handle_priv->interface_handle[i].dev_handle = file_handle;
- }
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- HANDLE handle;
- int i;
-
- if (sub_api == SUB_API_NOTSET)
- sub_api = priv->sub_api;
-
- if (!WinUSBX[sub_api].initialized)
- return;
-
- if (priv->apib->id == USB_API_COMPOSITE) {
- // If this is a composite device, just free and close all WinUSB-like
- // interfaces directly (each is independent and not associated with another)
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if (priv->usb_interface[i].apib->id == USB_API_WINUSBX) {
- handle = handle_priv->interface_handle[i].api_handle;
- if (HANDLE_VALID(handle))
- WinUSBX[sub_api].Free(handle);
-
- handle = handle_priv->interface_handle[i].dev_handle;
- if (HANDLE_VALID(handle))
- CloseHandle(handle);
- }
- }
- } else {
- // If this is a WinUSB device, free all interfaces above interface 0,
- // then free and close interface 0 last
- for (i = 1; i < USB_MAXINTERFACES; i++) {
- handle = handle_priv->interface_handle[i].api_handle;
- if (HANDLE_VALID(handle))
- WinUSBX[sub_api].Free(handle);
- }
- handle = handle_priv->interface_handle[0].api_handle;
- if (HANDLE_VALID(handle))
- WinUSBX[sub_api].Free(handle);
-
- handle = handle_priv->interface_handle[0].dev_handle;
- if (HANDLE_VALID(handle))
- CloseHandle(handle);
- }
-}
-
-static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- HANDLE winusb_handle = handle_priv->interface_handle[iface].api_handle;
- UCHAR policy;
- ULONG timeout = 0;
- uint8_t endpoint_address;
- int i;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- // With handle and enpoints set (in parent), we can setup the default pipe properties
- // see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx
- for (i = -1; i < priv->usb_interface[iface].nb_endpoints; i++) {
- endpoint_address = (i == -1) ? 0 : priv->usb_interface[iface].endpoint[i];
- if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout))
- usbi_dbg("failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address);
-
- if ((i == -1) || (sub_api == SUB_API_LIBUSB0))
- continue; // Other policies don't apply to control endpoint or libusb0
-
- policy = false;
- if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy))
- usbi_dbg("failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address);
-
- if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy))
- usbi_dbg("failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address);
-
- policy = true;
- /* ALLOW_PARTIAL_READS must be enabled due to likely libusbK bug. See:
- https://sourceforge.net/mailarchive/message.php?msg_id=29736015 */
- if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy))
- usbi_dbg("failed to enable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address);
-
- if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- AUTO_CLEAR_STALL, sizeof(UCHAR), &policy))
- usbi_dbg("failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address);
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE);
- SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL;
- HDEVINFO dev_info = INVALID_HANDLE_VALUE;
- SP_DEVINFO_DATA dev_info_data;
- char *dev_path_no_guid = NULL;
- char filter_path[] = "\\\\.\\libusb0-0000";
- bool found_filter = false;
- HANDLE file_handle, winusb_handle;
- DWORD err;
- int i;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- // If the device is composite, but using the default Windows composite parent driver (usbccgp)
- // or if it's the first WinUSB-like interface, we get a handle through Initialize().
- if ((is_using_usbccgp) || (iface == 0)) {
- // composite device (independent interfaces) or interface 0
- file_handle = handle_priv->interface_handle[iface].dev_handle;
- if (!HANDLE_VALID(file_handle))
- return LIBUSB_ERROR_NOT_FOUND;
-
- if (!WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
- handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
- err = GetLastError();
- switch(err) {
- case ERROR_BAD_COMMAND:
- // The device was disconnected
- usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- default:
- // it may be that we're using the libusb0 filter driver.
- // TODO: can we move this whole business into the K/0 DLL?
- for (i = 0; ; i++) {
- safe_free(dev_interface_details);
- safe_free(dev_path_no_guid);
-
- dev_interface_details = get_interface_details_filter(ctx, &dev_info, &dev_info_data, &GUID_DEVINTERFACE_LIBUSB0_FILTER, i, filter_path);
- if ((found_filter) || (dev_interface_details == NULL))
- break;
-
- // ignore GUID part
- dev_path_no_guid = sanitize_path(strtok(dev_interface_details->DevicePath, "{"));
- if (dev_path_no_guid == NULL)
- continue;
-
- if (strncmp(dev_path_no_guid, priv->usb_interface[iface].path, strlen(dev_path_no_guid)) == 0) {
- file_handle = CreateFileA(filter_path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
- if (file_handle != INVALID_HANDLE_VALUE) {
- if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
- // Replace the existing file handle with the working one
- CloseHandle(handle_priv->interface_handle[iface].dev_handle);
- handle_priv->interface_handle[iface].dev_handle = file_handle;
- found_filter = true;
- } else {
- usbi_err(ctx, "could not initialize filter driver for %s", filter_path);
- CloseHandle(file_handle);
- }
- } else {
- usbi_err(ctx, "could not open device %s: %s", filter_path, windows_error_str(0));
- }
- }
- }
- free(dev_interface_details);
- if (!found_filter) {
- usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(err));
- return LIBUSB_ERROR_ACCESS;
- }
- }
- }
- handle_priv->interface_handle[iface].api_handle = winusb_handle;
- } else {
- // For all other interfaces, use GetAssociatedInterface()
- winusb_handle = handle_priv->interface_handle[0].api_handle;
- // It is a requirement for multiple interface devices on Windows that, to you
- // must first claim the first interface before you claim the others
- if (!HANDLE_VALID(winusb_handle)) {
- file_handle = handle_priv->interface_handle[0].dev_handle;
- if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
- handle_priv->interface_handle[0].api_handle = winusb_handle;
- usbi_warn(ctx, "auto-claimed interface 0 (required to claim %d with WinUSB)", iface);
- } else {
- usbi_warn(ctx, "failed to auto-claim interface 0 (required to claim %d with WinUSB): %s", iface, windows_error_str(0));
- return LIBUSB_ERROR_ACCESS;
- }
- }
- if (!WinUSBX[sub_api].GetAssociatedInterface(winusb_handle, (UCHAR)(iface - 1),
- &handle_priv->interface_handle[iface].api_handle)) {
- handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
- switch(GetLastError()) {
- case ERROR_NO_MORE_ITEMS: // invalid iface
- return LIBUSB_ERROR_NOT_FOUND;
- case ERROR_BAD_COMMAND: // The device was disconnected
- return LIBUSB_ERROR_NO_DEVICE;
- case ERROR_ALREADY_EXISTS: // already claimed
- return LIBUSB_ERROR_BUSY;
- default:
- usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0));
- return LIBUSB_ERROR_ACCESS;
- }
- }
- }
- usbi_dbg("claimed interface %d", iface);
- handle_priv->active_interface = iface;
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- HANDLE winusb_handle;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- winusb_handle = handle_priv->interface_handle[iface].api_handle;
- if (!HANDLE_VALID(winusb_handle))
- return LIBUSB_ERROR_NOT_FOUND;
-
- WinUSBX[sub_api].Free(winusb_handle);
- handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
-
- return LIBUSB_SUCCESS;
-}
-
-/*
- * Return the first valid interface (of the same API type), for control transfers
- */
-static int get_valid_interface(struct libusb_device_handle *dev_handle, int api_id)
-{
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- int i;
-
- if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) {
- usbi_dbg("unsupported API ID");
- return -1;
- }
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if (HANDLE_VALID(handle_priv->interface_handle[i].dev_handle)
- && HANDLE_VALID(handle_priv->interface_handle[i].api_handle)
- && (priv->usb_interface[i].apib->id == api_id))
- return i;
- }
-
- return -1;
-}
-
-/*
- * Lookup interface by endpoint address. -1 if not found
- */
-static int interface_by_endpoint(struct windows_device_priv *priv,
- struct windows_device_handle_priv *handle_priv, uint8_t endpoint_address)
-{
- int i, j;
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if (!HANDLE_VALID(handle_priv->interface_handle[i].api_handle))
- continue;
- if (priv->usb_interface[i].endpoint == NULL)
- continue;
- for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) {
- if (priv->usb_interface[i].endpoint[j] == endpoint_address)
- return i;
- }
- }
-
- return -1;
-}
-
-static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
- WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer;
- ULONG size;
- HANDLE winusb_handle;
- int current_interface;
- struct winfd wfd;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- transfer_priv->pollable_fd = INVALID_WINFD;
- size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
-
- // Windows places upper limits on the control transfer size
- // See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff538112.aspx
- if (size > MAX_CTRL_BUFFER_LENGTH)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- current_interface = get_valid_interface(transfer->dev_handle, USB_API_WINUSBX);
- if (current_interface < 0) {
- if (auto_claim(transfer, &current_interface, USB_API_WINUSBX) != LIBUSB_SUCCESS)
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg("will use interface %d", current_interface);
- winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
-
- wfd = usbi_create_fd(winusb_handle, RW_READ, NULL, NULL);
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- if (wfd.fd < 0)
- return LIBUSB_ERROR_NO_MEM;
-
- // Sending of set configuration control requests from WinUSB creates issues
- if (((setup->request_type & (0x03 << 5)) == LIBUSB_REQUEST_TYPE_STANDARD)
- && (setup->request == LIBUSB_REQUEST_SET_CONFIGURATION)) {
- if (setup->value != priv->active_config) {
- usbi_warn(ctx, "cannot set configuration other than the default one");
- usbi_free_fd(&wfd);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- wfd.overlapped->InternalHigh = 0;
- } else {
- if (!WinUSBX[sub_api].ControlTransfer(wfd.handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, wfd.overlapped)) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_warn(ctx, "ControlTransfer failed: %s", windows_error_str(0));
- usbi_free_fd(&wfd);
- return LIBUSB_ERROR_IO;
- }
- } else {
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- wfd.overlapped->InternalHigh = (DWORD)size;
- }
- }
-
- // Use priv_transfer to store data needed for async polling
- transfer_priv->pollable_fd = wfd;
- transfer_priv->interface_number = (uint8_t)current_interface;
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- HANDLE winusb_handle;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- if (altsetting > 255)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- winusb_handle = handle_priv->interface_handle[iface].api_handle;
- if (!HANDLE_VALID(winusb_handle)) {
- usbi_err(ctx, "interface must be claimed first");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- if (!WinUSBX[sub_api].SetCurrentAlternateSetting(winusb_handle, (UCHAR)altsetting)) {
- usbi_err(ctx, "SetCurrentAlternateSetting failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_IO;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- HANDLE winusb_handle;
- bool ret;
- int current_interface;
- struct winfd wfd;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- transfer_priv->pollable_fd = INVALID_WINFD;
-
- current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
- if (current_interface < 0) {
- usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
-
- winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
-
- wfd = usbi_create_fd(winusb_handle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- if (wfd.fd < 0)
- return LIBUSB_ERROR_NO_MEM;
-
- if (IS_XFERIN(transfer)) {
- usbi_dbg("reading %d bytes", transfer->length);
- ret = WinUSBX[sub_api].ReadPipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped);
- } else {
- usbi_dbg("writing %d bytes", transfer->length);
- ret = WinUSBX[sub_api].WritePipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped);
- }
-
- if (!ret) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
- usbi_free_fd(&wfd);
- return LIBUSB_ERROR_IO;
- }
- } else {
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- wfd.overlapped->InternalHigh = (DWORD)transfer->length;
- }
-
- transfer_priv->pollable_fd = wfd;
- transfer_priv->interface_number = (uint8_t)current_interface;
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- HANDLE winusb_handle;
- int current_interface;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
- if (current_interface < 0) {
- usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface);
- winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
-
- if (!WinUSBX[sub_api].ResetPipe(winusb_handle, endpoint)) {
- usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-/*
- * from http://www.winvistatips.com/winusb-bugchecks-t335323.html (confirmed
- * through testing as well):
- * "You can not call WinUsb_AbortPipe on control pipe. You can possibly cancel
- * the control transfer using CancelIo"
- */
-static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer)
-{
- // Cancelling of the I/O is done in the parent
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- HANDLE winusb_handle;
- int current_interface;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- current_interface = transfer_priv->interface_number;
- if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) {
- usbi_err(ctx, "program assertion failed: invalid interface_number");
- return LIBUSB_ERROR_NOT_FOUND;
- }
- usbi_dbg("will use interface %d", current_interface);
-
- winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
-
- if (!WinUSBX[sub_api].AbortPipe(winusb_handle, transfer->endpoint)) {
- usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-/*
- * from the "How to Use WinUSB to Communicate with a USB Device" Microsoft white paper
- * (http://www.microsoft.com/whdc/connect/usb/winusb_howto.mspx):
- * "WinUSB does not support host-initiated reset port and cycle port operations" and
- * IOCTL_INTERNAL_USB_CYCLE_PORT is only available in kernel mode and the
- * IOCTL_USB_HUB_CYCLE_PORT ioctl was removed from Vista => the best we can do is
- * cycle the pipes (and even then, the control pipe can not be reset using WinUSB)
- */
-// TODO: (post hotplug): see if we can force eject the device and redetect it (reuse hotplug?)
-static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- struct winfd wfd;
- HANDLE winusb_handle;
- int i, j;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- // Reset any available pipe (except control)
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- winusb_handle = handle_priv->interface_handle[i].api_handle;
- for (wfd = handle_to_winfd(winusb_handle); wfd.fd > 0; ) {
- // Cancel any pollable I/O
- usbi_remove_pollfd(ctx, wfd.fd);
- usbi_free_fd(&wfd);
- wfd = handle_to_winfd(winusb_handle);
- }
-
- if (HANDLE_VALID(winusb_handle)) {
- for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) {
- usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]);
- if (!WinUSBX[sub_api].AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))
- usbi_err(ctx, "AbortPipe (pipe address %02X) failed: %s",
- priv->usb_interface[i].endpoint[j], windows_error_str(0));
-
- // FlushPipe seems to fail on OUT pipes
- if (IS_EPIN(priv->usb_interface[i].endpoint[j])
- && (!WinUSBX[sub_api].FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j])))
- usbi_err(ctx, "FlushPipe (pipe address %02X) failed: %s",
- priv->usb_interface[i].endpoint[j], windows_error_str(0));
-
- if (!WinUSBX[sub_api].ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))
- usbi_err(ctx, "ResetPipe (pipe address %02X) failed: %s",
- priv->usb_interface[i].endpoint[j], windows_error_str(0));
- }
- }
- }
-
- // libusbK & libusb0 have the ability to issue an actual device reset
- if (WinUSBX[sub_api].ResetDevice != NULL) {
- winusb_handle = handle_priv->interface_handle[0].api_handle;
- if (HANDLE_VALID(winusb_handle))
- WinUSBX[sub_api].ResetDevice(winusb_handle);
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size)
-{
- itransfer->transferred += io_size;
- return LIBUSB_TRANSFER_COMPLETED;
-}
-
-/*
- * Internal HID Support functions (from libusb-win32)
- * Note that functions that complete data transfer synchronously must return
- * LIBUSB_COMPLETED instead of LIBUSB_SUCCESS
- */
-static int _hid_get_hid_descriptor(struct hid_device_priv *dev, void *data, size_t *size);
-static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, size_t *size);
-
-static int _hid_wcslen(WCHAR *str)
-{
- int i = 0;
-
- while (str[i] && (str[i] != 0x409))
- i++;
-
- return i;
-}
-
-static int _hid_get_device_descriptor(struct hid_device_priv *dev, void *data, size_t *size)
-{
- struct libusb_device_descriptor d;
-
- d.bLength = LIBUSB_DT_DEVICE_SIZE;
- d.bDescriptorType = LIBUSB_DT_DEVICE;
- d.bcdUSB = 0x0200; /* 2.00 */
- d.bDeviceClass = 0;
- d.bDeviceSubClass = 0;
- d.bDeviceProtocol = 0;
- d.bMaxPacketSize0 = 64; /* fix this! */
- d.idVendor = (uint16_t)dev->vid;
- d.idProduct = (uint16_t)dev->pid;
- d.bcdDevice = 0x0100;
- d.iManufacturer = dev->string_index[0];
- d.iProduct = dev->string_index[1];
- d.iSerialNumber = dev->string_index[2];
- d.bNumConfigurations = 1;
-
- if (*size > LIBUSB_DT_DEVICE_SIZE)
- *size = LIBUSB_DT_DEVICE_SIZE;
- memcpy(data, &d, *size);
-
- return LIBUSB_COMPLETED;
-}
-
-static int _hid_get_config_descriptor(struct hid_device_priv *dev, void *data, size_t *size)
-{
- char num_endpoints = 0;
- size_t config_total_len = 0;
- char tmp[HID_MAX_CONFIG_DESC_SIZE];
- struct libusb_config_descriptor *cd;
- struct libusb_interface_descriptor *id;
- struct libusb_hid_descriptor *hd;
- struct libusb_endpoint_descriptor *ed;
- size_t tmp_size;
-
- if (dev->input_report_size)
- num_endpoints++;
- if (dev->output_report_size)
- num_endpoints++;
-
- config_total_len = LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE
- + LIBUSB_DT_HID_SIZE + num_endpoints * LIBUSB_DT_ENDPOINT_SIZE;
-
- cd = (struct libusb_config_descriptor *)tmp;
- id = (struct libusb_interface_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE);
- hd = (struct libusb_hid_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE
- + LIBUSB_DT_INTERFACE_SIZE);
- ed = (struct libusb_endpoint_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE
- + LIBUSB_DT_INTERFACE_SIZE
- + LIBUSB_DT_HID_SIZE);
-
- cd->bLength = LIBUSB_DT_CONFIG_SIZE;
- cd->bDescriptorType = LIBUSB_DT_CONFIG;
- cd->wTotalLength = (uint16_t)config_total_len;
- cd->bNumInterfaces = 1;
- cd->bConfigurationValue = 1;
- cd->iConfiguration = 0;
- cd->bmAttributes = 1 << 7; /* bus powered */
- cd->MaxPower = 50;
-
- id->bLength = LIBUSB_DT_INTERFACE_SIZE;
- id->bDescriptorType = LIBUSB_DT_INTERFACE;
- id->bInterfaceNumber = 0;
- id->bAlternateSetting = 0;
- id->bNumEndpoints = num_endpoints;
- id->bInterfaceClass = 3;
- id->bInterfaceSubClass = 0;
- id->bInterfaceProtocol = 0;
- id->iInterface = 0;
-
- tmp_size = LIBUSB_DT_HID_SIZE;
- _hid_get_hid_descriptor(dev, hd, &tmp_size);
-
- if (dev->input_report_size) {
- ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
- ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
- ed->bEndpointAddress = HID_IN_EP;
- ed->bmAttributes = 3;
- ed->wMaxPacketSize = dev->input_report_size - 1;
- ed->bInterval = 10;
- ed = (struct libusb_endpoint_descriptor *)((char *)ed + LIBUSB_DT_ENDPOINT_SIZE);
- }
-
- if (dev->output_report_size) {
- ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
- ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
- ed->bEndpointAddress = HID_OUT_EP;
- ed->bmAttributes = 3;
- ed->wMaxPacketSize = dev->output_report_size - 1;
- ed->bInterval = 10;
- }
-
- if (*size > config_total_len)
- *size = config_total_len;
- memcpy(data, tmp, *size);
-
- return LIBUSB_COMPLETED;
-}
-
-static int _hid_get_string_descriptor(struct hid_device_priv *dev, int _index,
- void *data, size_t *size)
-{
- void *tmp = NULL;
- size_t tmp_size = 0;
- int i;
-
- /* language ID, EN-US */
- char string_langid[] = {0x09, 0x04};
-
- if ((*size < 2) || (*size > 255))
- return LIBUSB_ERROR_OVERFLOW;
-
- if (_index == 0) {
- tmp = string_langid;
- tmp_size = sizeof(string_langid) + 2;
- } else {
- for (i = 0; i < 3; i++) {
- if (_index == (dev->string_index[i])) {
- tmp = dev->string[i];
- tmp_size = (_hid_wcslen(dev->string[i]) + 1) * sizeof(WCHAR);
- break;
- }
- }
-
- if (i == 3) // not found
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- if (!tmp_size)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- if (tmp_size < *size)
- *size = tmp_size;
-
- // 2 byte header
- ((uint8_t *)data)[0] = (uint8_t)*size;
- ((uint8_t *)data)[1] = LIBUSB_DT_STRING;
- memcpy((uint8_t *)data + 2, tmp, *size - 2);
-
- return LIBUSB_COMPLETED;
-}
-
-static int _hid_get_hid_descriptor(struct hid_device_priv *dev, void *data, size_t *size)
-{
- struct libusb_hid_descriptor d;
- uint8_t tmp[MAX_HID_DESCRIPTOR_SIZE];
- size_t report_len = MAX_HID_DESCRIPTOR_SIZE;
-
- _hid_get_report_descriptor(dev, tmp, &report_len);
-
- d.bLength = LIBUSB_DT_HID_SIZE;
- d.bDescriptorType = LIBUSB_DT_HID;
- d.bcdHID = 0x0110; /* 1.10 */
- d.bCountryCode = 0;
- d.bNumDescriptors = 1;
- d.bClassDescriptorType = LIBUSB_DT_REPORT;
- d.wClassDescriptorLength = (uint16_t)report_len;
-
- if (*size > LIBUSB_DT_HID_SIZE)
- *size = LIBUSB_DT_HID_SIZE;
- memcpy(data, &d, *size);
-
- return LIBUSB_COMPLETED;
-}
-
-static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, size_t *size)
-{
- uint8_t d[MAX_HID_DESCRIPTOR_SIZE];
- size_t i = 0;
-
- /* usage page (0xFFA0 == vendor defined) */
- d[i++] = 0x06; d[i++] = 0xA0; d[i++] = 0xFF;
- /* usage (vendor defined) */
- d[i++] = 0x09; d[i++] = 0x01;
- /* start collection (application) */
- d[i++] = 0xA1; d[i++] = 0x01;
- /* input report */
- if (dev->input_report_size) {
- /* usage (vendor defined) */
- d[i++] = 0x09; d[i++] = 0x01;
- /* logical minimum (0) */
- d[i++] = 0x15; d[i++] = 0x00;
- /* logical maximum (255) */
- d[i++] = 0x25; d[i++] = 0xFF;
- /* report size (8 bits) */
- d[i++] = 0x75; d[i++] = 0x08;
- /* report count */
- d[i++] = 0x95; d[i++] = (uint8_t)dev->input_report_size - 1;
- /* input (data, variable, absolute) */
- d[i++] = 0x81; d[i++] = 0x00;
- }
- /* output report */
- if (dev->output_report_size) {
- /* usage (vendor defined) */
- d[i++] = 0x09; d[i++] = 0x02;
- /* logical minimum (0) */
- d[i++] = 0x15; d[i++] = 0x00;
- /* logical maximum (255) */
- d[i++] = 0x25; d[i++] = 0xFF;
- /* report size (8 bits) */
- d[i++] = 0x75; d[i++] = 0x08;
- /* report count */
- d[i++] = 0x95; d[i++] = (uint8_t)dev->output_report_size - 1;
- /* output (data, variable, absolute) */
- d[i++] = 0x91; d[i++] = 0x00;
- }
- /* feature report */
- if (dev->feature_report_size) {
- /* usage (vendor defined) */
- d[i++] = 0x09; d[i++] = 0x03;
- /* logical minimum (0) */
- d[i++] = 0x15; d[i++] = 0x00;
- /* logical maximum (255) */
- d[i++] = 0x25; d[i++] = 0xFF;
- /* report size (8 bits) */
- d[i++] = 0x75; d[i++] = 0x08;
- /* report count */
- d[i++] = 0x95; d[i++] = (uint8_t)dev->feature_report_size - 1;
- /* feature (data, variable, absolute) */
- d[i++] = 0xb2; d[i++] = 0x02; d[i++] = 0x01;
- }
-
- /* end collection */
- d[i++] = 0xC0;
-
- if (*size > i)
- *size = i;
- memcpy(data, d, *size);
-
- return LIBUSB_COMPLETED;
-}
-
-static int _hid_get_descriptor(struct hid_device_priv *dev, HANDLE hid_handle, int recipient,
- int type, int _index, void *data, size_t *size)
-{
- switch(type) {
- case LIBUSB_DT_DEVICE:
- usbi_dbg("LIBUSB_DT_DEVICE");
- return _hid_get_device_descriptor(dev, data, size);
- case LIBUSB_DT_CONFIG:
- usbi_dbg("LIBUSB_DT_CONFIG");
- if (!_index)
- return _hid_get_config_descriptor(dev, data, size);
- return LIBUSB_ERROR_INVALID_PARAM;
- case LIBUSB_DT_STRING:
- usbi_dbg("LIBUSB_DT_STRING");
- return _hid_get_string_descriptor(dev, _index, data, size);
- case LIBUSB_DT_HID:
- usbi_dbg("LIBUSB_DT_HID");
- if (!_index)
- return _hid_get_hid_descriptor(dev, data, size);
- return LIBUSB_ERROR_INVALID_PARAM;
- case LIBUSB_DT_REPORT:
- usbi_dbg("LIBUSB_DT_REPORT");
- if (!_index)
- return _hid_get_report_descriptor(dev, data, size);
- return LIBUSB_ERROR_INVALID_PARAM;
- case LIBUSB_DT_PHYSICAL:
- usbi_dbg("LIBUSB_DT_PHYSICAL");
- if (HidD_GetPhysicalDescriptor(hid_handle, data, (ULONG)*size))
- return LIBUSB_COMPLETED;
- return LIBUSB_ERROR_OTHER;
- }
-
- usbi_dbg("unsupported");
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int _hid_get_report(struct hid_device_priv *dev, HANDLE hid_handle, int id, void *data,
- struct windows_transfer_priv *tp, size_t *size, OVERLAPPED *overlapped, int report_type)
-{
- uint8_t *buf;
- DWORD ioctl_code, read_size, expected_size = (DWORD)*size;
- int r = LIBUSB_SUCCESS;
-
- if (tp->hid_buffer != NULL)
- usbi_dbg("program assertion failed: hid_buffer is not NULL");
-
- if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) {
- usbi_dbg("invalid size (%u)", *size);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- switch (report_type) {
- case HID_REPORT_TYPE_INPUT:
- ioctl_code = IOCTL_HID_GET_INPUT_REPORT;
- break;
- case HID_REPORT_TYPE_FEATURE:
- ioctl_code = IOCTL_HID_GET_FEATURE;
- break;
- default:
- usbi_dbg("unknown HID report type %d", report_type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- // Add a trailing byte to detect overflows
- buf = calloc(1, expected_size + 1);
- if (buf == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- buf[0] = (uint8_t)id; // Must be set always
- usbi_dbg("report ID: 0x%02X", buf[0]);
-
- tp->hid_expected_size = expected_size;
- read_size = expected_size;
-
- // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
- if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size + 1,
- buf, expected_size + 1, &read_size, overlapped)) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_dbg("Failed to Read HID Report: %s", windows_error_str(0));
- free(buf);
- return LIBUSB_ERROR_IO;
- }
- // Asynchronous wait
- tp->hid_buffer = buf;
- tp->hid_dest = data; // copy dest, as not necessarily the start of the transfer buffer
- return LIBUSB_SUCCESS;
- }
-
- // Transfer completed synchronously => copy and discard extra buffer
- if (read_size == 0) {
- usbi_warn(NULL, "program assertion failed - read completed synchronously, but no data was read");
- *size = 0;
- } else {
- if (buf[0] != id)
- usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id);
-
- if ((size_t)read_size > expected_size) {
- r = LIBUSB_ERROR_OVERFLOW;
- usbi_dbg("OVERFLOW!");
- } else {
- r = LIBUSB_COMPLETED;
- }
-
- *size = MIN((size_t)read_size, *size);
- if (id == 0)
- memcpy(data, buf + 1, *size); // Discard report ID
- else
- memcpy(data, buf, *size);
- }
-
- free(buf);
- return r;
-}
-
-static int _hid_set_report(struct hid_device_priv *dev, HANDLE hid_handle, int id, void *data,
- struct windows_transfer_priv *tp, size_t *size, OVERLAPPED *overlapped, int report_type)
-{
- uint8_t *buf = NULL;
- DWORD ioctl_code, write_size = (DWORD)*size;
-
- if (tp->hid_buffer != NULL)
- usbi_dbg("program assertion failed: hid_buffer is not NULL");
-
- if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) {
- usbi_dbg("invalid size (%u)", *size);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- switch (report_type) {
- case HID_REPORT_TYPE_OUTPUT:
- ioctl_code = IOCTL_HID_SET_OUTPUT_REPORT;
- break;
- case HID_REPORT_TYPE_FEATURE:
- ioctl_code = IOCTL_HID_SET_FEATURE;
- break;
- default:
- usbi_dbg("unknown HID report type %d", report_type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- usbi_dbg("report ID: 0x%02X", id);
- // When report IDs are not used (i.e. when id == 0), we must add
- // a null report ID. Otherwise, we just use original data buffer
- if (id == 0)
- write_size++;
-
- buf = malloc(write_size);
- if (buf == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- if (id == 0) {
- buf[0] = 0;
- memcpy(buf + 1, data, *size);
- } else {
- // This seems like a waste, but if we don't duplicate the
- // data, we'll get issues when freeing hid_buffer
- memcpy(buf, data, *size);
- if (buf[0] != id)
- usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id);
- }
-
- // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
- if (!DeviceIoControl(hid_handle, ioctl_code, buf, write_size,
- buf, write_size, &write_size, overlapped)) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_dbg("Failed to Write HID Output Report: %s", windows_error_str(0));
- free(buf);
- return LIBUSB_ERROR_IO;
- }
- tp->hid_buffer = buf;
- tp->hid_dest = NULL;
- return LIBUSB_SUCCESS;
- }
-
- // Transfer completed synchronously
- *size = write_size;
- if (write_size == 0)
- usbi_dbg("program assertion failed - write completed synchronously, but no data was written");
-
- free(buf);
- return LIBUSB_COMPLETED;
-}
-
-static int _hid_class_request(struct hid_device_priv *dev, HANDLE hid_handle, int request_type,
- int request, int value, int _index, void *data, struct windows_transfer_priv *tp,
- size_t *size, OVERLAPPED *overlapped)
-{
- int report_type = (value >> 8) & 0xFF;
- int report_id = value & 0xFF;
-
- if ((LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_INTERFACE)
- && (LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_DEVICE))
- return LIBUSB_ERROR_INVALID_PARAM;
-
- if (LIBUSB_REQ_OUT(request_type) && request == HID_REQ_SET_REPORT)
- return _hid_set_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type);
-
- if (LIBUSB_REQ_IN(request_type) && request == HID_REQ_GET_REPORT)
- return _hid_get_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type);
-
- return LIBUSB_ERROR_INVALID_PARAM;
-}
-
-
-/*
- * HID API functions
- */
-static int hid_init(int sub_api, struct libusb_context *ctx)
-{
- DLL_GET_HANDLE(hid);
- DLL_LOAD_FUNC(hid, HidD_GetAttributes, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetHidGuid, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetPreparsedData, TRUE);
- DLL_LOAD_FUNC(hid, HidD_FreePreparsedData, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetManufacturerString, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetProductString, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetSerialNumberString, TRUE);
- DLL_LOAD_FUNC(hid, HidP_GetCaps, TRUE);
- DLL_LOAD_FUNC(hid, HidD_SetNumInputBuffers, TRUE);
- DLL_LOAD_FUNC(hid, HidD_SetFeature, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetFeature, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetPhysicalDescriptor, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetInputReport, FALSE);
- DLL_LOAD_FUNC(hid, HidD_SetOutputReport, FALSE);
- DLL_LOAD_FUNC(hid, HidD_FlushQueue, TRUE);
- DLL_LOAD_FUNC(hid, HidP_GetValueCaps, TRUE);
-
- api_hid_available = true;
- return LIBUSB_SUCCESS;
-}
-
-static int hid_exit(int sub_api)
-{
- DLL_FREE_HANDLE(hid);
-
- return LIBUSB_SUCCESS;
-}
-
-// NB: open and close must ensure that they only handle interface of
-// the right API type, as these functions can be called wholesale from
-// composite_open(), with interfaces belonging to different APIs
-static int hid_open(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- HIDD_ATTRIBUTES hid_attributes;
- PHIDP_PREPARSED_DATA preparsed_data = NULL;
- HIDP_CAPS capabilities;
- HIDP_VALUE_CAPS *value_caps;
- HANDLE hid_handle = INVALID_HANDLE_VALUE;
- int i, j;
- // report IDs handling
- ULONG size[3];
- int nb_ids[2]; // zero and nonzero report IDs
-#if defined(ENABLE_LOGGING)
- const char *type[3] = {"input", "output", "feature"};
-#endif
-
- CHECK_HID_AVAILABLE;
-
- if (priv->hid == NULL) {
- usbi_err(ctx, "program assertion failed - private HID structure is unitialized");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if ((priv->usb_interface[i].path != NULL)
- && (priv->usb_interface[i].apib->id == USB_API_HID)) {
- hid_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
- /*
- * http://www.lvr.com/hidfaq.htm: Why do I receive "Access denied" when attempting to access my HID?
- * "Windows 2000 and later have exclusive read/write access to HIDs that are configured as a system
- * keyboards or mice. An application can obtain a handle to a system keyboard or mouse by not
- * requesting READ or WRITE access with CreateFile. Applications can then use HidD_SetFeature and
- * HidD_GetFeature (if the device supports Feature reports)."
- */
- if (hid_handle == INVALID_HANDLE_VALUE) {
- usbi_warn(ctx, "could not open HID device in R/W mode (keyboard or mouse?) - trying without");
- hid_handle = CreateFileA(priv->usb_interface[i].path, 0, FILE_SHARE_WRITE | FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
- if (hid_handle == INVALID_HANDLE_VALUE) {
- usbi_err(ctx, "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0));
- switch(GetLastError()) {
- case ERROR_FILE_NOT_FOUND: // The device was disconnected
- return LIBUSB_ERROR_NO_DEVICE;
- case ERROR_ACCESS_DENIED:
- return LIBUSB_ERROR_ACCESS;
- default:
- return LIBUSB_ERROR_IO;
- }
- }
- priv->usb_interface[i].restricted_functionality = true;
- }
- handle_priv->interface_handle[i].api_handle = hid_handle;
- }
- }
-
- hid_attributes.Size = sizeof(hid_attributes);
- do {
- if (!HidD_GetAttributes(hid_handle, &hid_attributes)) {
- usbi_err(ctx, "could not gain access to HID top collection (HidD_GetAttributes)");
- break;
- }
-
- priv->hid->vid = hid_attributes.VendorID;
- priv->hid->pid = hid_attributes.ProductID;
-
- // Set the maximum available input buffer size
- for (i = 32; HidD_SetNumInputBuffers(hid_handle, i); i *= 2);
- usbi_dbg("set maximum input buffer size to %d", i / 2);
-
- // Get the maximum input and output report size
- if (!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) {
- usbi_err(ctx, "could not read HID preparsed data (HidD_GetPreparsedData)");
- break;
- }
- if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) {
- usbi_err(ctx, "could not parse HID capabilities (HidP_GetCaps)");
- break;
- }
-
- // Find out if interrupt will need report IDs
- size[0] = capabilities.NumberInputValueCaps;
- size[1] = capabilities.NumberOutputValueCaps;
- size[2] = capabilities.NumberFeatureValueCaps;
- for (j = HidP_Input; j <= HidP_Feature; j++) {
- usbi_dbg("%u HID %s report value(s) found", (unsigned int)size[j], type[j]);
- priv->hid->uses_report_ids[j] = false;
- if (size[j] > 0) {
- value_caps = calloc(size[j], sizeof(HIDP_VALUE_CAPS));
- if ((value_caps != NULL)
- && (HidP_GetValueCaps((HIDP_REPORT_TYPE)j, value_caps, &size[j], preparsed_data) == HIDP_STATUS_SUCCESS)
- && (size[j] >= 1)) {
- nb_ids[0] = 0;
- nb_ids[1] = 0;
- for (i = 0; i < (int)size[j]; i++) {
- usbi_dbg(" Report ID: 0x%02X", value_caps[i].ReportID);
- if (value_caps[i].ReportID != 0)
- nb_ids[1]++;
- else
- nb_ids[0]++;
- }
- if (nb_ids[1] != 0) {
- if (nb_ids[0] != 0)
- usbi_warn(ctx, "program assertion failed: zero and nonzero report IDs used for %s",
- type[j]);
- priv->hid->uses_report_ids[j] = true;
- }
- } else {
- usbi_warn(ctx, " could not process %s report IDs", type[j]);
- }
- free(value_caps);
- }
- }
-
- // Set the report sizes
- priv->hid->input_report_size = capabilities.InputReportByteLength;
- priv->hid->output_report_size = capabilities.OutputReportByteLength;
- priv->hid->feature_report_size = capabilities.FeatureReportByteLength;
-
- // Fetch string descriptors
- priv->hid->string_index[0] = priv->dev_descriptor.iManufacturer;
- if (priv->hid->string_index[0] != 0)
- HidD_GetManufacturerString(hid_handle, priv->hid->string[0], sizeof(priv->hid->string[0]));
- else
- priv->hid->string[0][0] = 0;
-
- priv->hid->string_index[1] = priv->dev_descriptor.iProduct;
- if (priv->hid->string_index[1] != 0)
- HidD_GetProductString(hid_handle, priv->hid->string[1], sizeof(priv->hid->string[1]));
- else
- priv->hid->string[1][0] = 0;
-
- priv->hid->string_index[2] = priv->dev_descriptor.iSerialNumber;
- if (priv->hid->string_index[2] != 0)
- HidD_GetSerialNumberString(hid_handle, priv->hid->string[2], sizeof(priv->hid->string[2]));
- else
- priv->hid->string[2][0] = 0;
- } while(0);
-
- if (preparsed_data)
- HidD_FreePreparsedData(preparsed_data);
-
- return LIBUSB_SUCCESS;
-}
-
-static void hid_close(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- HANDLE file_handle;
- int i;
-
- if (!api_hid_available)
- return;
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if (priv->usb_interface[i].apib->id == USB_API_HID) {
- file_handle = handle_priv->interface_handle[i].api_handle;
- if (HANDLE_VALID(file_handle))
- CloseHandle(file_handle);
- }
- }
-}
-
-static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
-
- CHECK_HID_AVAILABLE;
-
- // NB: Disconnection detection is not possible in this function
- if (priv->usb_interface[iface].path == NULL)
- return LIBUSB_ERROR_NOT_FOUND; // invalid iface
-
- // We use dev_handle as a flag for interface claimed
- if (handle_priv->interface_handle[iface].dev_handle == INTERFACE_CLAIMED)
- return LIBUSB_ERROR_BUSY; // already claimed
-
-
- handle_priv->interface_handle[iface].dev_handle = INTERFACE_CLAIMED;
-
- usbi_dbg("claimed interface %d", iface);
- handle_priv->active_interface = iface;
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
-
- CHECK_HID_AVAILABLE;
-
- if (priv->usb_interface[iface].path == NULL)
- return LIBUSB_ERROR_NOT_FOUND; // invalid iface
-
- if (handle_priv->interface_handle[iface].dev_handle != INTERFACE_CLAIMED)
- return LIBUSB_ERROR_NOT_FOUND; // invalid iface
-
- handle_priv->interface_handle[iface].dev_handle = INVALID_HANDLE_VALUE;
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
-
- CHECK_HID_AVAILABLE;
-
- if (altsetting > 255)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- if (altsetting != 0) {
- usbi_err(ctx, "set interface altsetting not supported for altsetting >0");
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer;
- HANDLE hid_handle;
- struct winfd wfd;
- int current_interface, config;
- size_t size;
- int r = LIBUSB_ERROR_INVALID_PARAM;
-
- CHECK_HID_AVAILABLE;
-
- transfer_priv->pollable_fd = INVALID_WINFD;
- safe_free(transfer_priv->hid_buffer);
- transfer_priv->hid_dest = NULL;
- size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
-
- if (size > MAX_CTRL_BUFFER_LENGTH)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- current_interface = get_valid_interface(transfer->dev_handle, USB_API_HID);
- if (current_interface < 0) {
- if (auto_claim(transfer, &current_interface, USB_API_HID) != LIBUSB_SUCCESS)
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg("will use interface %d", current_interface);
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- wfd = usbi_create_fd(hid_handle, RW_READ, NULL, NULL);
- if (wfd.fd < 0)
- return LIBUSB_ERROR_NOT_FOUND;
-
- switch(LIBUSB_REQ_TYPE(setup->request_type)) {
- case LIBUSB_REQUEST_TYPE_STANDARD:
- switch(setup->request) {
- case LIBUSB_REQUEST_GET_DESCRIPTOR:
- r = _hid_get_descriptor(priv->hid, wfd.handle, LIBUSB_REQ_RECIPIENT(setup->request_type),
- (setup->value >> 8) & 0xFF, setup->value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size);
- break;
- case LIBUSB_REQUEST_GET_CONFIGURATION:
- r = windows_get_configuration(transfer->dev_handle, &config);
- if (r == LIBUSB_SUCCESS) {
- size = 1;
- ((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = (uint8_t)config;
- r = LIBUSB_COMPLETED;
- }
- break;
- case LIBUSB_REQUEST_SET_CONFIGURATION:
- if (setup->value == priv->active_config) {
- r = LIBUSB_COMPLETED;
- } else {
- usbi_warn(ctx, "cannot set configuration other than the default one");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- }
- break;
- case LIBUSB_REQUEST_GET_INTERFACE:
- size = 1;
- ((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = 0;
- r = LIBUSB_COMPLETED;
- break;
- case LIBUSB_REQUEST_SET_INTERFACE:
- r = hid_set_interface_altsetting(0, transfer->dev_handle, setup->index, setup->value);
- if (r == LIBUSB_SUCCESS)
- r = LIBUSB_COMPLETED;
- break;
- default:
- usbi_warn(ctx, "unsupported HID control request");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
- break;
- case LIBUSB_REQUEST_TYPE_CLASS:
- r = _hid_class_request(priv->hid, wfd.handle, setup->request_type, setup->request, setup->value,
- setup->index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv,
- &size, wfd.overlapped);
- break;
- default:
- usbi_warn(ctx, "unsupported HID control request");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
-
- if (r == LIBUSB_COMPLETED) {
- // Force request to be completed synchronously. Transferred size has been set by previous call
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- // http://msdn.microsoft.com/en-us/library/ms684342%28VS.85%29.aspx
- // set InternalHigh to the number of bytes transferred
- wfd.overlapped->InternalHigh = (DWORD)size;
- r = LIBUSB_SUCCESS;
- }
-
- if (r == LIBUSB_SUCCESS) {
- // Use priv_transfer to store data needed for async polling
- transfer_priv->pollable_fd = wfd;
- transfer_priv->interface_number = (uint8_t)current_interface;
- } else {
- usbi_free_fd(&wfd);
- }
-
- return r;
-}
-
-static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- struct winfd wfd;
- HANDLE hid_handle;
- bool direction_in, ret;
- int current_interface, length;
- DWORD size;
- int r = LIBUSB_SUCCESS;
-
- CHECK_HID_AVAILABLE;
-
- transfer_priv->pollable_fd = INVALID_WINFD;
- transfer_priv->hid_dest = NULL;
- safe_free(transfer_priv->hid_buffer);
-
- current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
- if (current_interface < 0) {
- usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
-
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
- direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
-
- wfd = usbi_create_fd(hid_handle, direction_in?RW_READ:RW_WRITE, NULL, NULL);
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- if (wfd.fd < 0)
- return LIBUSB_ERROR_NO_MEM;
-
- // If report IDs are not in use, an extra prefix byte must be added
- if (((direction_in) && (!priv->hid->uses_report_ids[0]))
- || ((!direction_in) && (!priv->hid->uses_report_ids[1])))
- length = transfer->length + 1;
- else
- length = transfer->length;
-
- // Add a trailing byte to detect overflows on input
- transfer_priv->hid_buffer = calloc(1, length + 1);
- if (transfer_priv->hid_buffer == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- transfer_priv->hid_expected_size = length;
-
- if (direction_in) {
- transfer_priv->hid_dest = transfer->buffer;
- usbi_dbg("reading %d bytes (report ID: 0x00)", length);
- ret = ReadFile(wfd.handle, transfer_priv->hid_buffer, length + 1, &size, wfd.overlapped);
- } else {
- if (!priv->hid->uses_report_ids[1])
- memcpy(transfer_priv->hid_buffer + 1, transfer->buffer, transfer->length);
- else
- // We could actually do without the calloc and memcpy in this case
- memcpy(transfer_priv->hid_buffer, transfer->buffer, transfer->length);
-
- usbi_dbg("writing %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]);
- ret = WriteFile(wfd.handle, transfer_priv->hid_buffer, length, &size, wfd.overlapped);
- }
-
- if (!ret) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_err(ctx, "HID transfer failed: %s", windows_error_str(0));
- usbi_free_fd(&wfd);
- safe_free(transfer_priv->hid_buffer);
- return LIBUSB_ERROR_IO;
- }
- } else {
- // Only write operations that completed synchronously need to free up
- // hid_buffer. For reads, copy_transfer_data() handles that process.
- if (!direction_in)
- safe_free(transfer_priv->hid_buffer);
-
- if (size == 0) {
- usbi_err(ctx, "program assertion failed - no data was transferred");
- size = 1;
- }
- if (size > (size_t)length) {
- usbi_err(ctx, "OVERFLOW!");
- r = LIBUSB_ERROR_OVERFLOW;
- }
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- wfd.overlapped->InternalHigh = size;
- }
-
- transfer_priv->pollable_fd = wfd;
- transfer_priv->interface_number = (uint8_t)current_interface;
-
- return r;
-}
-
-static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
- HANDLE hid_handle;
- int current_interface;
-
- CHECK_HID_AVAILABLE;
-
- current_interface = transfer_priv->interface_number;
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
- CancelIo(hid_handle);
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- HANDLE hid_handle;
- int current_interface;
-
- CHECK_HID_AVAILABLE;
-
- // Flushing the queues on all interfaces is the best we can achieve
- for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) {
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
- if (HANDLE_VALID(hid_handle))
- HidD_FlushQueue(hid_handle);
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- HANDLE hid_handle;
- int current_interface;
-
- CHECK_HID_AVAILABLE;
-
- current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
- if (current_interface < 0) {
- usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface);
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
-
- // No endpoint selection with Microsoft's implementation, so we try to flush the
- // whole interface. Should be OK for most case scenarios
- if (!HidD_FlushQueue(hid_handle)) {
- usbi_err(ctx, "Flushing of HID queue failed: %s", windows_error_str(0));
- // Device was probably disconnected
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-// This extra function is only needed for HID
-static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- int r = LIBUSB_TRANSFER_COMPLETED;
- uint32_t corrected_size = io_size;
-
- if (transfer_priv->hid_buffer != NULL) {
- // If we have a valid hid_buffer, it means the transfer was async
- if (transfer_priv->hid_dest != NULL) { // Data readout
- if (corrected_size > 0) {
- // First, check for overflow
- if (corrected_size > transfer_priv->hid_expected_size) {
- usbi_err(ctx, "OVERFLOW!");
- corrected_size = (uint32_t)transfer_priv->hid_expected_size;
- r = LIBUSB_TRANSFER_OVERFLOW;
- }
-
- if (transfer_priv->hid_buffer[0] == 0) {
- // Discard the 1 byte report ID prefix
- corrected_size--;
- memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer + 1, corrected_size);
- } else {
- memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, corrected_size);
- }
- }
- transfer_priv->hid_dest = NULL;
- }
- // For write, we just need to free the hid buffer
- safe_free(transfer_priv->hid_buffer);
- }
-
- itransfer->transferred += corrected_size;
- return r;
-}
-
-
-/*
- * Composite API functions
- */
-static int composite_init(int sub_api, struct libusb_context *ctx)
-{
- return LIBUSB_SUCCESS;
-}
-
-static int composite_exit(int sub_api)
-{
- return LIBUSB_SUCCESS;
-}
-
-static int composite_open(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- int r = LIBUSB_ERROR_NOT_FOUND;
- uint8_t i;
- // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID
- bool available[SUB_API_MAX + 1] = { 0 };
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- switch (priv->usb_interface[i].apib->id) {
- case USB_API_WINUSBX:
- if (priv->usb_interface[i].sub_api != SUB_API_NOTSET)
- available[priv->usb_interface[i].sub_api] = true;
- break;
- case USB_API_HID:
- available[SUB_API_MAX] = true;
- break;
- default:
- break;
- }
- }
-
- for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers
- if (available[i]) {
- r = usb_api_backend[USB_API_WINUSBX].open(i, dev_handle);
- if (r != LIBUSB_SUCCESS)
- return r;
- }
- }
-
- if (available[SUB_API_MAX]) // HID driver
- r = hid_open(SUB_API_NOTSET, dev_handle);
-
- return r;
-}
-
-static void composite_close(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- uint8_t i;
- // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID
- bool available[SUB_API_MAX + 1] = { 0 };
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- switch (priv->usb_interface[i].apib->id) {
- case USB_API_WINUSBX:
- if (priv->usb_interface[i].sub_api != SUB_API_NOTSET)
- available[priv->usb_interface[i].sub_api] = true;
- break;
- case USB_API_HID:
- available[SUB_API_MAX] = true;
- break;
- default:
- break;
- }
- }
-
- for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers
- if (available[i])
- usb_api_backend[USB_API_WINUSBX].close(i, dev_handle);
- }
-
- if (available[SUB_API_MAX]) // HID driver
- hid_close(SUB_API_NOTSET, dev_handle);
-}
-
-static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
-
- return priv->usb_interface[iface].apib->
- claim_interface(priv->usb_interface[iface].sub_api, dev_handle, iface);
-}
-
-static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
-
- return priv->usb_interface[iface].apib->
- set_interface_altsetting(priv->usb_interface[iface].sub_api, dev_handle, iface, altsetting);
-}
-
-static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
-
- return priv->usb_interface[iface].apib->
- release_interface(priv->usb_interface[iface].sub_api, dev_handle, iface);
-}
-
-static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- struct libusb_config_descriptor *conf_desc;
- WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer;
- int iface, pass, r;
-
- // Interface shouldn't matter for control, but it does in practice, with Windows'
- // restrictions with regards to accessing HID keyboards and mice. Try to target
- // a specific interface first, if possible.
- switch (LIBUSB_REQ_RECIPIENT(setup->request_type)) {
- case LIBUSB_RECIPIENT_INTERFACE:
- iface = setup->index & 0xFF;
- break;
- case LIBUSB_RECIPIENT_ENDPOINT:
- r = libusb_get_active_config_descriptor(transfer->dev_handle->dev, &conf_desc);
- if (r == LIBUSB_SUCCESS) {
- iface = get_interface_by_endpoint(conf_desc, (setup->index & 0xFF));
- libusb_free_config_descriptor(conf_desc);
- break;
- }
- // Fall through if not able to determine interface
- default:
- iface = -1;
- break;
- }
-
- // Try and target a specific interface if the control setup indicates such
- if ((iface >= 0) && (iface < USB_MAXINTERFACES)) {
- usbi_dbg("attempting control transfer targeted to interface %d", iface);
- if (priv->usb_interface[iface].path != NULL) {
- r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer);
- if (r == LIBUSB_SUCCESS)
- return r;
- }
- }
-
- // Either not targeted to a specific interface or no luck in doing so.
- // Try a 2 pass approach with all interfaces.
- for (pass = 0; pass < 2; pass++) {
- for (iface = 0; iface < USB_MAXINTERFACES; iface++) {
- if (priv->usb_interface[iface].path != NULL) {
- if ((pass == 0) && (priv->usb_interface[iface].restricted_functionality)) {
- usbi_dbg("trying to skip restricted interface #%d (HID keyboard or mouse?)", iface);
- continue;
- }
- usbi_dbg("using interface %d", iface);
- r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer);
- // If not supported on this API, it may be supported on another, so don't give up yet!!
- if (r == LIBUSB_ERROR_NOT_SUPPORTED)
- continue;
- return r;
- }
- }
- }
-
- usbi_err(ctx, "no libusb supported interfaces to complete request");
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) {
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- int current_interface;
-
- current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
- if (current_interface < 0) {
- usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- return priv->usb_interface[current_interface].apib->
- submit_bulk_transfer(priv->usb_interface[current_interface].sub_api, itransfer);
-}
-
-static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) {
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- int current_interface;
-
- current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
- if (current_interface < 0) {
- usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- return priv->usb_interface[current_interface].apib->
- submit_iso_transfer(priv->usb_interface[current_interface].sub_api, itransfer);
-}
-
-static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- int current_interface;
-
- current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
- if (current_interface < 0) {
- usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- return priv->usb_interface[current_interface].apib->
- clear_halt(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint);
-}
-
-static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
-
- return priv->usb_interface[transfer_priv->interface_number].apib->
- abort_control(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer);
-}
-
-static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
-
- return priv->usb_interface[transfer_priv->interface_number].apib->
- abort_transfers(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer);
-}
-
-static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- int r;
- uint8_t i;
- bool available[SUB_API_MAX];
-
- for (i = 0; i < SUB_API_MAX; i++)
- available[i] = false;
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if ((priv->usb_interface[i].apib->id == USB_API_WINUSBX)
- && (priv->usb_interface[i].sub_api != SUB_API_NOTSET))
- available[priv->usb_interface[i].sub_api] = true;
- }
-
- for (i = 0; i < SUB_API_MAX; i++) {
- if (available[i]) {
- r = usb_api_backend[USB_API_WINUSBX].reset_device(i, dev_handle);
- if (r != LIBUSB_SUCCESS)
- return r;
- }
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
-
- return priv->usb_interface[transfer_priv->interface_number].apib->
- copy_transfer_data(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer, io_size);
-}
-
-#endif /* !USE_USBDK */
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/version_nano.h b/vendor/github.com/karalabe/hid/libusb/libusb/version_nano.h
deleted file mode 100644
index 0a5d1c992..000000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/version_nano.h
+++ /dev/null
@@ -1 +0,0 @@
-#define LIBUSB_NANO 11182
diff --git a/vendor/github.com/karalabe/usb/AUTHORS b/vendor/github.com/karalabe/usb/AUTHORS
new file mode 100644
index 000000000..4112a92f3
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/AUTHORS
@@ -0,0 +1,6 @@
+Felix Lange <fjl@twurst.com>
+Guillaume Ballet <gballet@gmail.com>
+Jakob Weisblat <jakobw@yubico.com>
+Mateusz Mikołajczyk <mikolajczyk.mateusz@gmail.com>
+Péter Szilágyi <peterke@gmail.com>
+Rosen Penev <rosenp@gmail.com>
diff --git a/vendor/github.com/karalabe/usb/LICENSE b/vendor/github.com/karalabe/usb/LICENSE
new file mode 100644
index 000000000..65c5ca88a
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/LICENSE
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/vendor/github.com/karalabe/usb/README.md b/vendor/github.com/karalabe/usb/README.md
new file mode 100644
index 000000000..b6920f51a
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/README.md
@@ -0,0 +1,47 @@
+[![Travis][travisimg]][travisurl]
+[![AppVeyor][appveyorimg]][appveyorurl]
+[![GoDoc][docimg]][docurl]
+
+[travisimg]: https://travis-ci.org/karalabe/usb.svg?branch=master
+[travisurl]: https://travis-ci.org/karalabe/usb
+[appveyorimg]: https://ci.appveyor.com/api/projects/status/u96eq262bj2itprh/branch/master?svg=true
+[appveyorurl]: https://ci.appveyor.com/project/karalabe/usb
+[docimg]: https://godoc.org/github.com/karalabe/usb?status.svg
+[docurl]: https://godoc.org/github.com/karalabe/usb
+
+# Yet another USB library for Go
+
+The `usb` package is a cross platform, fully self-contained library for accessing and communicating with USB devices **either via HID or low level interrupts**. The goal of the library was to create a simple way to find-, attach to- and read/write form USB devices.
+
+There are multiple already existing USB libraries:
+
+ * The original `gousb` package [created by @kylelemons](https://github.com/kylelemons/gousb) and nowadays [maintained by @google](https://github.com/google/gousb) is a CGO wrapper around `libusb`. It is the most advanced USB library for Go out there.
+ * Unfortunately, `gousb` requires the `libusb` C library to be installed both during build as well as during runtime on the host operating system. This breaks binary portability and also adds unnecessary hurdles on Windows.
+ * Furthermore, whilst HID devices are supported by `libusb`, the OS on Macos and Windows explicitly takes over these devices, so only native system calls can be used on recent versions (i.e. you **cannot** use `libusb` for HID).
+ * There is a fork of `gousb` [created by @karalabe](https://github.com/karalabe/gousb) that statically linked `libusb` during build, but with the lack of HID access, that work was abandoned.
+ * For HID-only devices, a previous self-contained package was created at [`github.com/karalabe/hid`](https://github.com/karalabe/hid), which worked well for hardware wallet uses cases in [`go-ethereum`](https://github.com/ethereum/go-ethereum). It's a simple package that does it's thing well.
+ * Unfortunately, `hid` is not capable of talking to generic USB devices. When multiple different devices are needed, eventually some will not support the HID spec (e.g. WebUSB). Pulling in both `hid` and `gousb` will break down due to both depending internally on different versions of `libusb` on Linux.
+
+This `usb` package is a proper integration of `hidapi` and `libusb` so that communication with HID devices is done via system calls, whereas communication with lower level USB devices is done via interrupts. All this detail is hidden away behind a tiny interface.
+
+The package supports Linux, macOS, Windows and FreeBSD. Exclude constraints are also specified for Android and iOS to allow smoother vendoring into cross platform projects.
+
+## Cross-compiling
+
+Using `go get`, the embedded C library is compiled into the binary format of your host OS. Cross compiling to a different platform or architecture entails disabling CGO by default in Go, causing device enumeration `hid.Enumerate()` to yield no results.
+
+To cross compile a functional version of this library, you'll need to enable CGO during cross compilation via `CGO_ENABLED=1` and you'll need to install and set a cross compilation enabled C toolkit via `CC=your-cross-gcc`.
+
+## Acknowledgements
+
+Although the `usb` package is an implementation from scratch, HID support was heavily inspired by the existing [`go.hid`](https://github.com/GeertJohan/go.hid) library, which seems abandoned since 2015; is incompatible with Go 1.6+; and has various external dependencies.
+
+Wide character support in the HID support is done via the [`gowchar`](https://github.com/orofarne/gowchar) library, unmaintained since 2013; non buildable with a modern Go release and failing `go vet` checks. As such, `gowchar` was also vendored in inline.
+
+Error handling for the `libusb` integration originates from the [`gousb`](https://github.com/google/gousb) library.
+
+## License
+
+This USB library is licensed under the [GNU Lesser General Public License v3.0](https://www.gnu.org/licenses/lgpl-3.0.en.html) (dictated by libusb).
+
+If you are only interested in Human Interface devices, a less restrictive package can be found at [`github.com/karalabe/hid`](https://github.com/karalabe/hid).
diff --git a/vendor/github.com/karalabe/hid/appveyor.yml b/vendor/github.com/karalabe/usb/appveyor.yml
index 84b3c95ff..8d2d3da55 100644
--- a/vendor/github.com/karalabe/hid/appveyor.yml
+++ b/vendor/github.com/karalabe/usb/appveyor.yml
@@ -1,7 +1,7 @@
os: Visual Studio 2015
# Clone directly into GOPATH.
-clone_folder: C:\gopath\src\github.com\karalabe\hid
+clone_folder: C:\gopath\src\github.com\karalabe\usb
clone_depth: 1
version: "{branch}.{build}"
environment:
@@ -22,8 +22,8 @@ environment:
install:
- rmdir C:\go /s /q
- - appveyor DownloadFile https://storage.googleapis.com/golang/go1.10.1.windows-%GOARCH%.zip
- - 7z x go1.10.1.windows-%GOARCH%.zip -y -oC:\ > NUL
+ - appveyor DownloadFile https://storage.googleapis.com/golang/go1.12.5.windows-%GOARCH%.zip
+ - 7z x go1.12.5.windows-%GOARCH%.zip -y -oC:\ > NUL
- go version
- gcc --version
diff --git a/vendor/github.com/karalabe/usb/demo.go b/vendor/github.com/karalabe/usb/demo.go
new file mode 100644
index 000000000..229faaf5f
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/demo.go
@@ -0,0 +1,76 @@
+// usb - Self contained USB and HID library for Go
+// Copyright 2019 The library Authors
+//
+// This library is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// The library is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License along
+// with the library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build none
+
+package main
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/karalabe/usb"
+)
+
+func main() {
+ // Enumerate all the HID devices in alphabetical path order
+ hids, err := usb.EnumerateHid(0, 0)
+ if err != nil {
+ panic(err)
+ }
+ for i := 0; i < len(hids); i++ {
+ for j := i + 1; j < len(hids); j++ {
+ if hids[i].Path > hids[j].Path {
+ hids[i], hids[j] = hids[j], hids[i]
+ }
+ }
+ }
+ for i, hid := range hids {
+ fmt.Println(strings.Repeat("-", 128))
+ fmt.Printf("HID #%d\n", i)
+ fmt.Printf(" OS Path: %s\n", hid.Path)
+ fmt.Printf(" Vendor ID: %#04x\n", hid.VendorID)
+ fmt.Printf(" Product ID: %#04x\n", hid.ProductID)
+ fmt.Printf(" Release: %d\n", hid.Release)
+ fmt.Printf(" Serial: %s\n", hid.Serial)
+ fmt.Printf(" Manufacturer: %s\n", hid.Manufacturer)
+ fmt.Printf(" Product: %s\n", hid.Product)
+ fmt.Printf(" Usage Page: %d\n", hid.UsagePage)
+ fmt.Printf(" Usage: %d\n", hid.Usage)
+ fmt.Printf(" Interface: %d\n", hid.Interface)
+ }
+ fmt.Println(strings.Repeat("=", 128))
+
+ // Enumerate all the non-HID devices in alphabetical path order
+ raws, err := usb.EnumerateRaw(0, 0)
+ if err != nil {
+ panic(err)
+ }
+ for i := 0; i < len(raws); i++ {
+ for j := i + 1; j < len(raws); j++ {
+ if raws[i].Path > raws[j].Path {
+ raws[i], raws[j] = raws[j], raws[i]
+ }
+ }
+ }
+ for i, raw := range raws {
+ fmt.Printf("RAW #%d\n", i)
+ fmt.Printf(" OS Path: %s\n", raw.Path)
+ fmt.Printf(" Vendor ID: %#04x\n", raw.VendorID)
+ fmt.Printf(" Product ID: %#04x\n", raw.ProductID)
+ fmt.Printf(" Interface: %d\n", raw.Interface)
+ fmt.Println(strings.Repeat("-", 128))
+ }
+}
diff --git a/vendor/github.com/karalabe/usb/go.mod b/vendor/github.com/karalabe/usb/go.mod
new file mode 100644
index 000000000..ef549d28f
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/go.mod
@@ -0,0 +1,3 @@
+module github.com/karalabe/usb
+
+go 1.12
diff --git a/vendor/github.com/karalabe/usb/hid_disabled.go b/vendor/github.com/karalabe/usb/hid_disabled.go
new file mode 100644
index 000000000..a85964bf3
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/hid_disabled.go
@@ -0,0 +1,42 @@
+// usb - Self contained USB and HID library for Go
+// Copyright 2017 The library Authors
+//
+// This library is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// The library is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License along
+// with the library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build !freebsd,!linux,!darwin,!windows ios !cgo
+
+package usb
+
+// HidDevice is a live HID USB connected device handle. On platforms that this file
+// implements, the type lacks the actual HID device and all methods are noop.
+type HidDevice struct {
+ DeviceInfo // Embed the infos for easier access
+}
+
+// Close releases the HID USB device handle. On platforms that this file implements,
+// the method is just a noop.
+func (dev *HidDevice) Close() error {
+ return ErrUnsupportedPlatform
+}
+
+// Write sends an output report to a HID device. On platforms that this file
+// implements, the method just returns an error.
+func (dev *HidDevice) Write(b []byte) (int, error) {
+ return 0, ErrUnsupportedPlatform
+}
+
+// Read retrieves an input report from a HID device. On platforms that this file
+// implements, the method just returns an error.
+func (dev *HidDevice) Read(b []byte) (int, error) {
+ return 0, ErrUnsupportedPlatform
+}
diff --git a/vendor/github.com/karalabe/hid/hid_enabled.go b/vendor/github.com/karalabe/usb/hid_enabled.go
index e95e5792d..c2b372098 100644
--- a/vendor/github.com/karalabe/hid/hid_enabled.go
+++ b/vendor/github.com/karalabe/usb/hid_enabled.go
@@ -1,44 +1,25 @@
-// hid - Gopher Interface Devices (USB HID)
-// Copyright (c) 2017 Péter Szilágyi. All rights reserved.
+// usb - Self contained USB and HID library for Go
+// Copyright 2017 The library Authors
//
-// This file is released under the 3-clause BSD license. Note however that Linux
-// support depends on libusb, released under LGNU GPL 2.1 or later.
+// This library is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// The library is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License along
+// with the library. If not, see <http://www.gnu.org/licenses/>.
-// +build linux,cgo darwin,!ios,cgo windows,cgo
+// +build freebsd,cgo linux,cgo darwin,!ios,cgo windows,cgo
-package hid
+package usb
/*
-#cgo CFLAGS: -I./hidapi/hidapi
-
-#cgo linux CFLAGS: -I./libusb/libusb -DDEFAULT_VISIBILITY="" -DOS_LINUX -D_GNU_SOURCE -DPOLL_NFDS_TYPE=int
-#cgo linux,!android LDFLAGS: -lrt
-#cgo darwin CFLAGS: -DOS_DARWIN
-#cgo darwin LDFLAGS: -framework CoreFoundation -framework IOKit
-#cgo windows CFLAGS: -DOS_WINDOWS
-#cgo windows LDFLAGS: -lsetupapi
-
-#ifdef OS_LINUX
- #include <sys/poll.h>
- #include "os/threads_posix.c"
- #include "os/poll_posix.c"
-
- #include "os/linux_usbfs.c"
- #include "os/linux_netlink.c"
-
- #include "core.c"
- #include "descriptor.c"
- #include "hotplug.c"
- #include "io.c"
- #include "strerror.c"
- #include "sync.c"
-
- #include "hidapi/libusb/hid.c"
-#elif OS_DARWIN
- #include "hidapi/mac/hid.c"
-#elif OS_WINDOWS
- #include "hidapi/windows/hid.c"
-#endif
+#include <stdlib.h>
+#include "./hidapi/hidapi/hidapi.h"
*/
import "C"
@@ -49,35 +30,16 @@ import (
"unsafe"
)
-// 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
-
-// Supported returns whether this platform is supported by the HID library or not.
-// The goal of this method is to allow programatically handling platforms that do
-// not support USB HID and not having to fall back to build constraints.
-func Supported() bool {
- return true
-}
-
-// Enumerate returns a list of all the HID devices attached to the system which
+// enumerateHid 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 Enumerate(vendorID uint16, productID uint16) []DeviceInfo {
- enumerateLock.Lock()
- defer enumerateLock.Unlock()
-
+func enumerateHid(vendorID uint16, productID uint16) ([]DeviceInfo, error) {
// 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
+ return nil, nil
}
defer C.hid_free_enumeration(head)
@@ -104,14 +66,11 @@ func Enumerate(vendorID uint16, productID uint16) []DeviceInfo {
}
infos = append(infos, info)
}
- return infos
+ return infos, nil
}
-// Open connects to an HID device by its path name.
-func (info DeviceInfo) Open() (*Device, error) {
- enumerateLock.Lock()
- defer enumerateLock.Unlock()
-
+// openHid connects to an HID device by its path name.
+func openHid(info DeviceInfo) (*hidDevice, error) {
path := C.CString(info.Path)
defer C.free(unsafe.Pointer(path))
@@ -119,14 +78,14 @@ func (info DeviceInfo) Open() (*Device, error) {
if device == nil {
return nil, errors.New("hidapi: failed to open device")
}
- return &Device{
+ return &hidDevice{
DeviceInfo: info,
device: device,
}, nil
}
-// Device is a live HID USB connected device handle.
-type Device struct {
+// hidDevice is a live HID USB connected device handle.
+type hidDevice struct {
DeviceInfo // Embed the infos for easier access
device *C.hid_device // Low level HID device to communicate through
@@ -134,7 +93,7 @@ type Device struct {
}
// Close releases the HID USB device handle.
-func (dev *Device) Close() error {
+func (dev *hidDevice) Close() error {
dev.lock.Lock()
defer dev.lock.Unlock()
@@ -149,7 +108,7 @@ func (dev *Device) Close() error {
//
// 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 *Device) Write(b []byte) (int, error) {
+func (dev *hidDevice) Write(b []byte) (int, error) {
// Abort if nothing to write
if len(b) == 0 {
return 0, nil
@@ -192,7 +151,7 @@ func (dev *Device) Write(b []byte) (int, error) {
}
// Read retrieves an input report from a HID device.
-func (dev *Device) Read(b []byte) (int, error) {
+func (dev *hidDevice) Read(b []byte) (int, error) {
// Aborth if nothing to read
if len(b) == 0 {
return 0, nil
diff --git a/vendor/github.com/karalabe/hid/hidapi/AUTHORS.txt b/vendor/github.com/karalabe/usb/hidapi/AUTHORS.txt
index 7acafd78c..7acafd78c 100644
--- a/vendor/github.com/karalabe/hid/hidapi/AUTHORS.txt
+++ b/vendor/github.com/karalabe/usb/hidapi/AUTHORS.txt
diff --git a/vendor/github.com/karalabe/hid/hidapi/LICENSE-bsd.txt b/vendor/github.com/karalabe/usb/hidapi/LICENSE-bsd.txt
index 538cdf95c..538cdf95c 100644
--- a/vendor/github.com/karalabe/hid/hidapi/LICENSE-bsd.txt
+++ b/vendor/github.com/karalabe/usb/hidapi/LICENSE-bsd.txt
diff --git a/vendor/github.com/karalabe/hid/hidapi/LICENSE-gpl3.txt b/vendor/github.com/karalabe/usb/hidapi/LICENSE-gpl3.txt
index 94a9ed024..94a9ed024 100644
--- a/vendor/github.com/karalabe/hid/hidapi/LICENSE-gpl3.txt
+++ b/vendor/github.com/karalabe/usb/hidapi/LICENSE-gpl3.txt
diff --git a/vendor/github.com/karalabe/hid/hidapi/LICENSE-orig.txt b/vendor/github.com/karalabe/usb/hidapi/LICENSE-orig.txt
index e3f338082..e3f338082 100644
--- a/vendor/github.com/karalabe/hid/hidapi/LICENSE-orig.txt
+++ b/vendor/github.com/karalabe/usb/hidapi/LICENSE-orig.txt
diff --git a/vendor/github.com/karalabe/hid/hidapi/LICENSE.txt b/vendor/github.com/karalabe/usb/hidapi/LICENSE.txt
index e1676d4c4..e1676d4c4 100644
--- a/vendor/github.com/karalabe/hid/hidapi/LICENSE.txt
+++ b/vendor/github.com/karalabe/usb/hidapi/LICENSE.txt
diff --git a/vendor/github.com/karalabe/hid/hidapi/README.txt b/vendor/github.com/karalabe/usb/hidapi/README.txt
index f19dae4ab..f19dae4ab 100644
--- a/vendor/github.com/karalabe/hid/hidapi/README.txt
+++ b/vendor/github.com/karalabe/usb/hidapi/README.txt
diff --git a/vendor/github.com/karalabe/hid/hidapi/hidapi/hidapi.h b/vendor/github.com/karalabe/usb/hidapi/hidapi/hidapi.h
index e5bc2dc40..e5bc2dc40 100644
--- a/vendor/github.com/karalabe/hid/hidapi/hidapi/hidapi.h
+++ b/vendor/github.com/karalabe/usb/hidapi/hidapi/hidapi.h
diff --git a/vendor/github.com/karalabe/hid/hidapi/libusb/hid.c b/vendor/github.com/karalabe/usb/hidapi/libusb/hid.c
index 474dff41c..474dff41c 100644
--- a/vendor/github.com/karalabe/hid/hidapi/libusb/hid.c
+++ b/vendor/github.com/karalabe/usb/hidapi/libusb/hid.c
diff --git a/vendor/github.com/karalabe/hid/hidapi/mac/hid.c b/vendor/github.com/karalabe/usb/hidapi/mac/hid.c
index e0756a158..e0756a158 100644
--- a/vendor/github.com/karalabe/hid/hidapi/mac/hid.c
+++ b/vendor/github.com/karalabe/usb/hidapi/mac/hid.c
diff --git a/vendor/github.com/karalabe/hid/hidapi/windows/hid.c b/vendor/github.com/karalabe/usb/hidapi/windows/hid.c
index 86810d7e5..86810d7e5 100755..100644
--- a/vendor/github.com/karalabe/hid/hidapi/windows/hid.c
+++ b/vendor/github.com/karalabe/usb/hidapi/windows/hid.c
diff --git a/vendor/github.com/karalabe/usb/libs.go b/vendor/github.com/karalabe/usb/libs.go
new file mode 100644
index 000000000..94720fbd4
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/libs.go
@@ -0,0 +1,74 @@
+// usb - Self contained USB and HID library for Go
+// Copyright 2019 The library Authors
+//
+// This library is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// The library is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License along
+// with the library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build freebsd,cgo linux,cgo darwin,!ios,cgo windows,cgo
+
+package usb
+
+/*
+#cgo CFLAGS: -I./hidapi/hidapi
+#cgo CFLAGS: -I./libusb/libusb
+#cgo CFLAGS: -DDEFAULT_VISIBILITY=""
+#cgo CFLAGS: -DPOLL_NFDS_TYPE=int
+
+#cgo linux CFLAGS: -DOS_LINUX -D_GNU_SOURCE
+#cgo linux,!android LDFLAGS: -lrt
+#cgo darwin CFLAGS: -DOS_DARWIN -DHAVE_SYS_TIME_H
+#cgo darwin LDFLAGS: -framework CoreFoundation -framework IOKit -lobjc
+#cgo windows CFLAGS: -DOS_WINDOWS
+#cgo windows LDFLAGS: -lsetupapi
+#cgo freebsd CFLAGS: -DOS_FREEBSD
+#cgo freebsd LDFLAGS: -lusb
+#cgo openbsd CFLAGS: -DOS_OPENBSD
+
+#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(DOS_FREEBSD) || defined(OS_OPENBSD)
+ #include <poll.h>
+ #include "os/threads_posix.c"
+ #include "os/poll_posix.c"
+#elif defined(OS_WINDOWS)
+ #include "os/poll_windows.c"
+ #include "os/threads_windows.c"
+#endif
+
+#ifdef OS_LINUX
+ #include "os/linux_usbfs.c"
+ #include "os/linux_netlink.c"
+ #include "hidapi/libusb/hid.c"
+#elif OS_DARWIN
+ #include "os/darwin_usb.c"
+ #include "hidapi/mac/hid.c"
+#elif OS_WINDOWS
+ #include "os/windows_nt_common.c"
+ #include "os/windows_usbdk.c"
+ #include "os/windows_winusb.c"
+ #include "hidapi/windows/hid.c"
+#elif OS_FREEBSD
+ #include <libusb.h>
+ #include "hidapi/libusb/hid.c"
+#elif DOS_OPENBSD
+ #include "os/openbsd_usb.c"
+ #include "hidapi/libusb/hid.c"
+#endif
+
+#ifndef OS_FREEBSD
+ #include "core.c"
+ #include "descriptor.c"
+ #include "hotplug.c"
+ #include "io.c"
+ #include "strerror.c"
+ #include "sync.c"
+#endif
+*/
+import "C"
diff --git a/vendor/github.com/karalabe/hid/libusb/AUTHORS b/vendor/github.com/karalabe/usb/libusb/AUTHORS
index 70d407bd1..e90ad9bb2 100644
--- a/vendor/github.com/karalabe/hid/libusb/AUTHORS
+++ b/vendor/github.com/karalabe/usb/libusb/AUTHORS
@@ -8,14 +8,19 @@ Copyright © 2010-2012 Michael Plante <michael.plante@gmail.com>
Copyright © 2011-2013 Hans de Goede <hdegoede@redhat.com>
Copyright © 2012-2013 Martin Pieuchot <mpi@openbsd.org>
Copyright © 2012-2013 Toby Gray <toby.gray@realvnc.com>
-Copyright © 2013-2015 Chris Dickens <christopher.a.dickens@gmail.com>
+Copyright © 2013-2018 Chris Dickens <christopher.a.dickens@gmail.com>
Other contributors:
+Adrian Bunk
Akshay Jaggi
Alan Ott
Alan Stern
Alex Vatchenko
Andrew Fernandes
+Andy Chunyu
+Andy McFadden
+Angus Gratton
+Anil Nair
Anthony Clay
Antonio Ospite
Artem Egorkine
@@ -23,12 +28,17 @@ Aurelien Jarno
Bastien Nocera
Bei Zhang
Benjamin Dobell
+Brent Rector
Carl Karsten
+Christophe Zeitouny
Colin Walters
Dave Camarillo
David Engraf
David Moore
Davidlohr Bueso
+Dmitry Fleytman
+Doug Johnston
+Evan Hunter
Federico Manzan
Felipe Balbi
Florian Albrechtskirchinger
@@ -41,23 +51,34 @@ Hans Ulrich Niedermann
Hector Martin
Hoi-Ho Chan
Ilya Konstantinov
+Jakub Klama
James Hanko
+Jeffrey Nichols
+Johann Richard
John Sheu
+Jonathon Jongsma
+Joost Muller
+Josh Gao
Joshua Blake
Justin Bischoff
+KIMURA Masaru
Karsten Koenig
Konrad Rzepecki
Kuangye Guo
Lars Kanis
Lars Wirzenius
+Lei Chen
Luca Longinotti
Marcus Meissner
Markus Heidelberg
Martin Ettl
Martin Koegler
+Matthew Stapleton
Matthias Bolte
+Michel Zou
Mike Frysinger
Mikhail Gusarov
+Morgan Leborgne
Moritz Fischer
Ларионов Даниил
Nicholas Corgan
@@ -66,10 +87,17 @@ Orin Eman
Paul Fertser
Pekka Nikander
Rob Walker
+Romain Vimont
+Roman Kalashnikov
+Sameeh Jubran
Sean McBride
Sebastian Pipping
+Sergey Serb
Simon Haggett
Simon Newton
+Stefan Agner
+Stefan Tauner
+Steinar H. Gunderson
Thomas Röfer
Tim Hutt
Tim Roberts
@@ -81,9 +109,11 @@ Uri Lublin
Vasily Khoruzhick
Vegard Storheil Eriksen
Venkatesh Shukla
+Vianney le Clément de Saint-Marcq
+Victor Toso
Vitali Lovich
+William Skellenger
Xiaofan Chen
Zoltán Kovács
Роман Донченко
parafin
-xantares
diff --git a/vendor/github.com/karalabe/hid/libusb/COPYING b/vendor/github.com/karalabe/usb/libusb/COPYING
index 5ab7695ab..5ab7695ab 100644
--- a/vendor/github.com/karalabe/hid/libusb/COPYING
+++ b/vendor/github.com/karalabe/usb/libusb/COPYING
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/config.h b/vendor/github.com/karalabe/usb/libusb/libusb/config.h
index e004f03cd..e004f03cd 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/config.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/config.h
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/core.c b/vendor/github.com/karalabe/usb/libusb/libusb/core.c
index d45bfe177..50f92f6b1 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/core.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/core.c
@@ -44,32 +44,6 @@
#include "libusbi.h"
#include "hotplug.h"
-#if defined(OS_LINUX)
-const struct usbi_os_backend * const usbi_backend = &linux_usbfs_backend;
-#elif defined(OS_DARWIN)
-const struct usbi_os_backend * const usbi_backend = &darwin_backend;
-#elif defined(OS_OPENBSD)
-const struct usbi_os_backend * const usbi_backend = &openbsd_backend;
-#elif defined(OS_NETBSD)
-const struct usbi_os_backend * const usbi_backend = &netbsd_backend;
-#elif defined(OS_WINDOWS)
-
-#if defined(USE_USBDK)
-const struct usbi_os_backend * const usbi_backend = &usbdk_backend;
-#else
-const struct usbi_os_backend * const usbi_backend = &windows_backend;
-#endif
-
-#elif defined(OS_WINCE)
-const struct usbi_os_backend * const usbi_backend = &wince_backend;
-#elif defined(OS_HAIKU)
-const struct usbi_os_backend * const usbi_backend = &haiku_usb_raw_backend;
-#elif defined (OS_SUNOS)
-const struct usbi_os_backend * const usbi_backend = &sunos_backend;
-#else
-#error "Unsupported OS"
-#endif
-
struct libusb_context *usbi_default_context = NULL;
static const struct libusb_version libusb_version_internal =
{ LIBUSB_MAJOR, LIBUSB_MINOR, LIBUSB_MICRO, LIBUSB_NANO,
@@ -142,15 +116,17 @@ struct list_head active_contexts_list;
* libusb uses stderr for all logging. By default, logging is set to NONE,
* which means that no output will be produced. However, unless the library
* has been compiled with logging disabled, then any application calls to
- * libusb_set_debug(), or the setting of the environmental variable
- * LIBUSB_DEBUG outside of the application, can result in logging being
- * produced. Your application should therefore not close stderr, but instead
- * direct it to the null device if its output is undesirable.
- *
- * The libusb_set_debug() function can be used to enable logging of certain
- * messages. Under standard configuration, libusb doesn't really log much
- * so you are advised to use this function to enable all error/warning/
- * informational messages. It will help debug problems with your software.
+ * libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level), or the setting of the
+ * environmental variable LIBUSB_DEBUG outside of the application, can result
+ * in logging being produced. Your application should therefore not close
+ * stderr, but instead direct it to the null device if its output is
+ * undesirable.
+ *
+ * The libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) function can be
+ * used to enable logging of certain messages. Under standard configuration,
+ * libusb doesn't really log much so you are advised to use this function
+ * to enable all error/warning/ informational messages. It will help debug
+ * problems with your software.
*
* The logged messages are unstructured. There is no one-to-one correspondence
* between messages being logged and success or failure return codes from
@@ -165,18 +141,20 @@ struct list_head active_contexts_list;
*
* The LIBUSB_DEBUG environment variable can be used to enable message logging
* at run-time. This environment variable should be set to a log level number,
- * which is interpreted the same as the libusb_set_debug() parameter. When this
+ * which is interpreted the same as the
+ * libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) parameter. When this
* environment variable is set, the message logging verbosity level is fixed
- * and libusb_set_debug() effectively does nothing.
+ * and libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) effectively does
+ * nothing.
*
* libusb can be compiled without any logging functions, useful for embedded
- * systems. In this case, libusb_set_debug() and the LIBUSB_DEBUG environment
- * variable have no effects.
+ * systems. In this case, libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level)
+ * and the LIBUSB_DEBUG environment variable have no effects.
*
* libusb can also be compiled with verbose debugging messages always. When
* the library is compiled in this way, all messages of all verbosities are
- * always logged. libusb_set_debug() and the LIBUSB_DEBUG environment variable
- * have no effects.
+ * always logged. libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level) and
+ * the LIBUSB_DEBUG environment variable have no effects.
*
* \section remarks Other remarks
*
@@ -187,6 +165,20 @@ struct list_head active_contexts_list;
/**
* \page libusb_caveats Caveats
*
+ * \section fork Fork considerations
+ *
+ * libusb is <em>not</em> designed to work across fork() calls. Depending on
+ * the platform, there may be resources in the parent process that are not
+ * available to the child (e.g. the hotplug monitor thread on Linux). In
+ * addition, since the parent and child will share libusb's internal file
+ * descriptors, using libusb in any way from the child could cause the parent
+ * process's \ref libusb_context to get into an inconsistent state.
+ *
+ * On Linux, libusb's file descriptors will be marked as CLOEXEC, which means
+ * that it is safe to fork() and exec() without worrying about the child
+ * process needing to clean up state or having access to these file descriptors.
+ * Other platforms may not be so forgiving, so consider yourself warned!
+ *
* \section devresets Device resets
*
* The libusb_reset_device() function allows you to reset a device. If your
@@ -291,7 +283,6 @@ if (cfg != desired)
* information about the end of the short packet, and the user probably wanted
* that surplus data to arrive in the next logical transfer.
*
- *
* \section zlp Zero length packets
*
* - libusb is able to send a packet of zero length to an endpoint simply by
@@ -310,7 +301,7 @@ if (cfg != desired)
* developed modules may both use libusb.
*
* libusb is written to allow for these multiple user scenarios. The two
- * "instances" of libusb will not interfere: libusb_set_debug() calls
+ * "instances" of libusb will not interfere: libusb_set_option() calls
* from one user will not affect the same settings for other users, other
* users can continue using libusb after one of them calls libusb_exit(), etc.
*
@@ -435,6 +426,7 @@ if (cfg != desired)
* - libusb_set_debug()
* - libusb_set_interface_alt_setting()
* - libusb_set_iso_packet_lengths()
+ * - libusb_set_option()
* - libusb_setlocale()
* - libusb_set_pollfd_notifiers()
* - libusb_strerror()
@@ -478,6 +470,7 @@ if (cfg != desired)
* - \ref libusb_iso_sync_type
* - \ref libusb_iso_usage_type
* - \ref libusb_log_level
+ * - \ref libusb_option
* - \ref libusb_request_recipient
* - \ref libusb_request_type
* - \ref libusb_speed
@@ -680,7 +673,7 @@ struct discovered_devs *discovered_devs_append(
struct libusb_device *usbi_alloc_device(struct libusb_context *ctx,
unsigned long session_id)
{
- size_t priv_size = usbi_backend->device_priv_size;
+ size_t priv_size = usbi_backend.device_priv_size;
struct libusb_device *dev = calloc(1, sizeof(*dev) + priv_size);
int r;
@@ -824,8 +817,8 @@ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx,
/* backend provides hotplug support */
struct libusb_device *dev;
- if (usbi_backend->hotplug_poll)
- usbi_backend->hotplug_poll();
+ if (usbi_backend.hotplug_poll)
+ usbi_backend.hotplug_poll();
usbi_mutex_lock(&ctx->usb_devs_lock);
list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) {
@@ -839,7 +832,7 @@ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx,
usbi_mutex_unlock(&ctx->usb_devs_lock);
} else {
/* backend does not provide hotplug support */
- r = usbi_backend->get_device_list(ctx, &discdevs);
+ r = usbi_backend.get_device_list(ctx, &discdevs);
}
if (r < 0) {
@@ -1167,8 +1160,8 @@ void API_EXPORTED libusb_unref_device(libusb_device *dev)
libusb_unref_device(dev->parent_dev);
- if (usbi_backend->destroy_device)
- usbi_backend->destroy_device(dev);
+ if (usbi_backend.destroy_device)
+ usbi_backend.destroy_device(dev);
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
/* backend does not support hotplug */
@@ -1242,7 +1235,7 @@ int API_EXPORTED libusb_open(libusb_device *dev,
{
struct libusb_context *ctx = DEVICE_CTX(dev);
struct libusb_device_handle *_dev_handle;
- size_t priv_size = usbi_backend->device_handle_priv_size;
+ size_t priv_size = usbi_backend.device_handle_priv_size;
int r;
usbi_dbg("open %d.%d", dev->bus_number, dev->device_address);
@@ -1265,7 +1258,7 @@ int API_EXPORTED libusb_open(libusb_device *dev,
_dev_handle->claimed_interfaces = 0;
memset(&_dev_handle->os_priv, 0, priv_size);
- r = usbi_backend->open(_dev_handle);
+ r = usbi_backend.open(_dev_handle);
if (r < 0) {
usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r);
libusb_unref_device(dev);
@@ -1382,7 +1375,7 @@ static void do_close(struct libusb_context *ctx,
list_del(&dev_handle->list);
usbi_mutex_unlock(&ctx->open_devs_lock);
- usbi_backend->close(dev_handle);
+ usbi_backend.close(dev_handle);
libusb_unref_device(dev_handle->dev);
usbi_mutex_destroy(&dev_handle->lock);
free(dev_handle);
@@ -1491,8 +1484,8 @@ int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev_handle,
int r = LIBUSB_ERROR_NOT_SUPPORTED;
usbi_dbg("");
- if (usbi_backend->get_configuration)
- r = usbi_backend->get_configuration(dev_handle, config);
+ if (usbi_backend.get_configuration)
+ r = usbi_backend.get_configuration(dev_handle, config);
if (r == LIBUSB_ERROR_NOT_SUPPORTED) {
uint8_t tmp = 0;
@@ -1567,7 +1560,7 @@ int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev_handle,
int configuration)
{
usbi_dbg("configuration %d", configuration);
- return usbi_backend->set_configuration(dev_handle, configuration);
+ return usbi_backend.set_configuration(dev_handle, configuration);
}
/** \ingroup libusb_dev
@@ -1614,7 +1607,7 @@ int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev_handle,
if (dev_handle->claimed_interfaces & (1 << interface_number))
goto out;
- r = usbi_backend->claim_interface(dev_handle, interface_number);
+ r = usbi_backend.claim_interface(dev_handle, interface_number);
if (r == 0)
dev_handle->claimed_interfaces |= 1 << interface_number;
@@ -1657,7 +1650,7 @@ int API_EXPORTED libusb_release_interface(libusb_device_handle *dev_handle,
goto out;
}
- r = usbi_backend->release_interface(dev_handle, interface_number);
+ r = usbi_backend.release_interface(dev_handle, interface_number);
if (r == 0)
dev_handle->claimed_interfaces &= ~(1 << interface_number);
@@ -1707,7 +1700,7 @@ int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev_hand
}
usbi_mutex_unlock(&dev_handle->lock);
- return usbi_backend->set_interface_altsetting(dev_handle, interface_number,
+ return usbi_backend.set_interface_altsetting(dev_handle, interface_number,
alternate_setting);
}
@@ -1734,7 +1727,7 @@ int API_EXPORTED libusb_clear_halt(libusb_device_handle *dev_handle,
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- return usbi_backend->clear_halt(dev_handle, endpoint);
+ return usbi_backend.clear_halt(dev_handle, endpoint);
}
/** \ingroup libusb_dev
@@ -1762,7 +1755,7 @@ int API_EXPORTED libusb_reset_device(libusb_device_handle *dev_handle)
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- return usbi_backend->reset_device(dev_handle);
+ return usbi_backend.reset_device(dev_handle);
}
/** \ingroup libusb_asyncio
@@ -1794,8 +1787,8 @@ int API_EXPORTED libusb_alloc_streams(libusb_device_handle *dev_handle,
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- if (usbi_backend->alloc_streams)
- return usbi_backend->alloc_streams(dev_handle, num_streams, endpoints,
+ if (usbi_backend.alloc_streams)
+ return usbi_backend.alloc_streams(dev_handle, num_streams, endpoints,
num_endpoints);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
@@ -1821,8 +1814,8 @@ int API_EXPORTED libusb_free_streams(libusb_device_handle *dev_handle,
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- if (usbi_backend->free_streams)
- return usbi_backend->free_streams(dev_handle, endpoints,
+ if (usbi_backend.free_streams)
+ return usbi_backend.free_streams(dev_handle, endpoints,
num_endpoints);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
@@ -1859,8 +1852,8 @@ unsigned char * LIBUSB_CALL libusb_dev_mem_alloc(libusb_device_handle *dev_handl
if (!dev_handle->dev->attached)
return NULL;
- if (usbi_backend->dev_mem_alloc)
- return usbi_backend->dev_mem_alloc(dev_handle, length);
+ if (usbi_backend.dev_mem_alloc)
+ return usbi_backend.dev_mem_alloc(dev_handle, length);
else
return NULL;
}
@@ -1876,8 +1869,8 @@ unsigned char * LIBUSB_CALL libusb_dev_mem_alloc(libusb_device_handle *dev_handl
int API_EXPORTED libusb_dev_mem_free(libusb_device_handle *dev_handle,
unsigned char *buffer, size_t length)
{
- if (usbi_backend->dev_mem_free)
- return usbi_backend->dev_mem_free(dev_handle, buffer, length);
+ if (usbi_backend.dev_mem_free)
+ return usbi_backend.dev_mem_free(dev_handle, buffer, length);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
}
@@ -1907,8 +1900,8 @@ int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev_handle,
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- if (usbi_backend->kernel_driver_active)
- return usbi_backend->kernel_driver_active(dev_handle, interface_number);
+ if (usbi_backend.kernel_driver_active)
+ return usbi_backend.kernel_driver_active(dev_handle, interface_number);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
}
@@ -1942,8 +1935,8 @@ int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev_handle,
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- if (usbi_backend->detach_kernel_driver)
- return usbi_backend->detach_kernel_driver(dev_handle, interface_number);
+ if (usbi_backend.detach_kernel_driver)
+ return usbi_backend.detach_kernel_driver(dev_handle, interface_number);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
}
@@ -1976,8 +1969,8 @@ int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev_handle,
if (!dev_handle->dev->attached)
return LIBUSB_ERROR_NO_DEVICE;
- if (usbi_backend->attach_kernel_driver)
- return usbi_backend->attach_kernel_driver(dev_handle, interface_number);
+ if (usbi_backend.attach_kernel_driver)
+ return usbi_backend.attach_kernel_driver(dev_handle, interface_number);
else
return LIBUSB_ERROR_NOT_SUPPORTED;
}
@@ -2007,7 +2000,7 @@ int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev_handle,
int API_EXPORTED libusb_set_auto_detach_kernel_driver(
libusb_device_handle *dev_handle, int enable)
{
- if (!(usbi_backend->caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER))
+ if (!(usbi_backend.caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER))
return LIBUSB_ERROR_NOT_SUPPORTED;
dev_handle->auto_detach_kernel_driver = enable;
@@ -2015,37 +2008,100 @@ int API_EXPORTED libusb_set_auto_detach_kernel_driver(
}
/** \ingroup libusb_lib
- * Set log message verbosity.
- *
- * The default level is LIBUSB_LOG_LEVEL_NONE, which means no messages are ever
- * printed. If you choose to increase the message verbosity level, ensure
- * that your application does not close the stdout/stderr file descriptors.
+ * \deprecated Use libusb_set_option() instead using the
+ * \ref LIBUSB_OPTION_LOG_LEVEL option.
+ */
+void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level)
+{
+#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
+ USBI_GET_CONTEXT(ctx);
+ if (!ctx->debug_fixed) {
+ level = CLAMP(level, LIBUSB_LOG_LEVEL_NONE, LIBUSB_LOG_LEVEL_DEBUG);
+ ctx->debug = (enum libusb_log_level)level;
+ }
+#else
+ UNUSED(ctx);
+ UNUSED(level);
+#endif
+}
+
+/** \ingroup libusb_lib
+ * Set an option in the library.
*
- * You are advised to use level LIBUSB_LOG_LEVEL_WARNING. libusb is conservative
- * with its message logging and most of the time, will only log messages that
- * explain error conditions and other oddities. This will help you debug
- * your software.
+ * Use this function to configure a specific option within the library.
*
- * If the LIBUSB_DEBUG environment variable was set when libusb was
- * initialized, this function does nothing: the message verbosity is fixed
- * to the value in the environment variable.
+ * Some options require one or more arguments to be provided. Consult each
+ * option's documentation for specific requirements.
*
- * If libusb was compiled without any message logging, this function does
- * nothing: you'll never get any messages.
+ * Since version 1.0.22, \ref LIBUSB_API_VERSION >= 0x01000106
*
- * If libusb was compiled with verbose debug message logging, this function
- * does nothing: you'll always get messages from all levels.
+ * \param ctx context on which to operate
+ * \param option which option to set
+ * \param ... any required arguments for the specified option
*
- * \param ctx the context to operate on, or NULL for the default context
- * \param level debug level to set
+ * \returns LIBUSB_SUCCESS on success
+ * \returns LIBUSB_ERROR_INVALID_PARAM if the option or arguments are invalid
+ * \returns LIBUSB_ERROR_NOT_SUPPORTED if the option is valid but not supported
+ * on this platform
*/
-void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level)
+int API_EXPORTED libusb_set_option(libusb_context *ctx,
+ enum libusb_option option, ...)
{
+ int arg, r = LIBUSB_SUCCESS;
+ va_list ap;
+
USBI_GET_CONTEXT(ctx);
- if (!ctx->debug_fixed)
- ctx->debug = level;
+
+ va_start(ap, option);
+ switch (option) {
+ case LIBUSB_OPTION_LOG_LEVEL:
+ arg = va_arg(ap, int);
+ if (arg < LIBUSB_LOG_LEVEL_NONE || arg > LIBUSB_LOG_LEVEL_DEBUG) {
+ r = LIBUSB_ERROR_INVALID_PARAM;
+ break;
+ }
+#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
+ if (!ctx->debug_fixed)
+ ctx->debug = (enum libusb_log_level)arg;
+#endif
+ break;
+
+ /* Handle all backend-specific options here */
+ case LIBUSB_OPTION_USE_USBDK:
+ if (usbi_backend.set_option)
+ r = usbi_backend.set_option(ctx, option, ap);
+ else
+ r = LIBUSB_ERROR_NOT_SUPPORTED;
+ break;
+
+ default:
+ r = LIBUSB_ERROR_INVALID_PARAM;
+ }
+ va_end(ap);
+
+ return r;
}
+#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
+/* returns the log level as defined in the LIBUSB_DEBUG environment variable.
+ * if LIBUSB_DEBUG is not present or not a number, returns LIBUSB_LOG_LEVEL_NONE.
+ * value is clamped to ensure it is within the valid range of possibilities.
+ */
+static enum libusb_log_level get_env_debug_level(void)
+{
+ const char *dbg = getenv("LIBUSB_DEBUG");
+ enum libusb_log_level level;
+ if (dbg) {
+ int dbg_level = atoi(dbg);
+ dbg_level = CLAMP(dbg_level, LIBUSB_LOG_LEVEL_NONE, LIBUSB_LOG_LEVEL_DEBUG);
+ level = (enum libusb_log_level)dbg_level;
+ } else {
+ level = LIBUSB_LOG_LEVEL_NONE;
+ }
+ return level;
+}
+#endif
+
/** \ingroup libusb_lib
* Initialize libusb. This function must be called before calling any other
* libusb function.
@@ -2062,7 +2118,7 @@ void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level)
int API_EXPORTED libusb_init(libusb_context **context)
{
struct libusb_device *dev, *next;
- char *dbg = getenv("LIBUSB_DEBUG");
+ size_t priv_size = usbi_backend.context_priv_size;
struct libusb_context *ctx;
static int first_init = 1;
int r = 0;
@@ -2070,7 +2126,7 @@ int API_EXPORTED libusb_init(libusb_context **context)
usbi_mutex_static_lock(&default_context_lock);
if (!timestamp_origin.tv_sec) {
- usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &timestamp_origin);
+ usbi_backend.clock_gettime(USBI_CLOCK_REALTIME, &timestamp_origin);
}
if (!context && usbi_default_context) {
@@ -2080,22 +2136,18 @@ int API_EXPORTED libusb_init(libusb_context **context)
return 0;
}
- ctx = calloc(1, sizeof(*ctx));
+ ctx = calloc(1, sizeof(*ctx) + priv_size);
if (!ctx) {
r = LIBUSB_ERROR_NO_MEM;
goto err_unlock;
}
-#ifdef ENABLE_DEBUG_LOGGING
- ctx->debug = LIBUSB_LOG_LEVEL_DEBUG;
+#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
+ ctx->debug = get_env_debug_level();
+ if (ctx->debug != LIBUSB_LOG_LEVEL_NONE)
+ ctx->debug_fixed = 1;
#endif
- if (dbg) {
- ctx->debug = atoi(dbg);
- if (ctx->debug)
- ctx->debug_fixed = 1;
- }
-
/* default context should be initialized before calling usbi_dbg */
if (!usbi_default_context) {
usbi_default_context = ctx;
@@ -2112,6 +2164,7 @@ int API_EXPORTED libusb_init(libusb_context **context)
list_init(&ctx->usb_devs);
list_init(&ctx->open_devs);
list_init(&ctx->hotplug_cbs);
+ ctx->next_hotplug_cb_handle = 1;
usbi_mutex_static_lock(&active_contexts_lock);
if (first_init) {
@@ -2121,8 +2174,8 @@ int API_EXPORTED libusb_init(libusb_context **context)
list_add (&ctx->list, &active_contexts_list);
usbi_mutex_static_unlock(&active_contexts_lock);
- if (usbi_backend->init) {
- r = usbi_backend->init(ctx);
+ if (usbi_backend.init) {
+ r = usbi_backend.init(ctx);
if (r)
goto err_free_ctx;
}
@@ -2139,8 +2192,8 @@ int API_EXPORTED libusb_init(libusb_context **context)
return 0;
err_backend_exit:
- if (usbi_backend->exit)
- usbi_backend->exit();
+ if (usbi_backend.exit)
+ usbi_backend.exit(ctx);
err_free_ctx:
if (ctx == usbi_default_context) {
usbi_default_context = NULL;
@@ -2200,7 +2253,7 @@ void API_EXPORTED libusb_exit(struct libusb_context *ctx)
usbi_mutex_static_unlock(&active_contexts_lock);
if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
- usbi_hotplug_deregister_all(ctx);
+ usbi_hotplug_deregister(ctx, 1);
/*
* Ensure any pending unplug events are read from the hotplug
@@ -2230,8 +2283,8 @@ void API_EXPORTED libusb_exit(struct libusb_context *ctx)
usbi_warn(ctx, "application left some devices open");
usbi_io_exit(ctx);
- if (usbi_backend->exit)
- usbi_backend->exit();
+ if (usbi_backend.exit)
+ usbi_backend.exit(ctx);
usbi_mutex_destroy(&ctx->open_devs_lock);
usbi_mutex_destroy(&ctx->usb_devs_lock);
@@ -2253,15 +2306,17 @@ int API_EXPORTED libusb_has_capability(uint32_t capability)
case LIBUSB_CAP_HAS_CAPABILITY:
return 1;
case LIBUSB_CAP_HAS_HOTPLUG:
- return !(usbi_backend->get_device_list);
+ return !(usbi_backend.get_device_list);
case LIBUSB_CAP_HAS_HID_ACCESS:
- return (usbi_backend->caps & USBI_CAP_HAS_HID_ACCESS);
+ return (usbi_backend.caps & USBI_CAP_HAS_HID_ACCESS);
case LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER:
- return (usbi_backend->caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER);
+ return (usbi_backend.caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER);
}
return 0;
}
+#ifdef ENABLE_LOGGING
+
/* this is defined in libusbi.h if needed */
#ifdef LIBUSB_PRINTF_WIN32
/*
@@ -2301,10 +2356,9 @@ int usbi_vsnprintf(char *str, size_t size, const char *format, va_list ap)
return ret;
}
-#endif
+#endif /* LIBUSB_PRINTF_WIN32 */
-static void usbi_log_str(struct libusb_context *ctx,
- enum libusb_log_level level, const char * str)
+static void usbi_log_str(enum libusb_log_level level, const char *str)
{
#if defined(USE_SYSTEM_LOGGING_FACILITY)
#if defined(OS_WINDOWS)
@@ -2317,18 +2371,20 @@ static void usbi_log_str(struct libusb_context *ctx,
#elif defined(__ANDROID__)
int priority = ANDROID_LOG_UNKNOWN;
switch (level) {
- case LIBUSB_LOG_LEVEL_INFO: priority = ANDROID_LOG_INFO; break;
- case LIBUSB_LOG_LEVEL_WARNING: priority = ANDROID_LOG_WARN; break;
+ case LIBUSB_LOG_LEVEL_NONE: return;
case LIBUSB_LOG_LEVEL_ERROR: priority = ANDROID_LOG_ERROR; break;
+ case LIBUSB_LOG_LEVEL_WARNING: priority = ANDROID_LOG_WARN; break;
+ case LIBUSB_LOG_LEVEL_INFO: priority = ANDROID_LOG_INFO; break;
case LIBUSB_LOG_LEVEL_DEBUG: priority = ANDROID_LOG_DEBUG; break;
}
__android_log_write(priority, "libusb", str);
#elif defined(HAVE_SYSLOG_FUNC)
int syslog_level = LOG_INFO;
switch (level) {
- case LIBUSB_LOG_LEVEL_INFO: syslog_level = LOG_INFO; break;
- case LIBUSB_LOG_LEVEL_WARNING: syslog_level = LOG_WARNING; break;
+ case LIBUSB_LOG_LEVEL_NONE: return;
case LIBUSB_LOG_LEVEL_ERROR: syslog_level = LOG_ERR; break;
+ case LIBUSB_LOG_LEVEL_WARNING: syslog_level = LOG_WARNING; break;
+ case LIBUSB_LOG_LEVEL_INFO: syslog_level = LOG_INFO; break;
case LIBUSB_LOG_LEVEL_DEBUG: syslog_level = LOG_DEBUG; break;
}
syslog(syslog_level, "%s", str);
@@ -2339,14 +2395,13 @@ static void usbi_log_str(struct libusb_context *ctx,
#else
fputs(str, stderr);
#endif /* USE_SYSTEM_LOGGING_FACILITY */
- UNUSED(ctx);
UNUSED(level);
}
void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
const char *function, const char *format, va_list args)
{
- const char *prefix = "";
+ const char *prefix;
char buf[USBI_MAX_LOG_LEN];
struct timespec now;
int global_debug, header_len, text_len;
@@ -2356,18 +2411,15 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
global_debug = 1;
UNUSED(ctx);
#else
- int ctx_level = 0;
+ enum libusb_log_level ctx_level = LIBUSB_LOG_LEVEL_NONE;
USBI_GET_CONTEXT(ctx);
- if (ctx) {
+ if (ctx)
ctx_level = ctx->debug;
- } else {
- char *dbg = getenv("LIBUSB_DEBUG");
- if (dbg)
- ctx_level = atoi(dbg);
- }
- global_debug = (ctx_level == LIBUSB_LOG_LEVEL_DEBUG);
- if (!ctx_level)
+ else
+ ctx_level = get_env_debug_level();
+
+ if (ctx_level == LIBUSB_LOG_LEVEL_NONE)
return;
if (level == LIBUSB_LOG_LEVEL_WARNING && ctx_level < LIBUSB_LOG_LEVEL_WARNING)
return;
@@ -2375,13 +2427,15 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
return;
if (level == LIBUSB_LOG_LEVEL_DEBUG && ctx_level < LIBUSB_LOG_LEVEL_DEBUG)
return;
+
+ global_debug = (ctx_level == LIBUSB_LOG_LEVEL_DEBUG);
#endif
- usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &now);
+ usbi_backend.clock_gettime(USBI_CLOCK_REALTIME, &now);
if ((global_debug) && (!has_debug_header_been_displayed)) {
has_debug_header_been_displayed = 1;
- usbi_log_str(ctx, LIBUSB_LOG_LEVEL_DEBUG, "[timestamp] [threadID] facility level [function call] <message>" USBI_LOG_LINE_END);
- usbi_log_str(ctx, LIBUSB_LOG_LEVEL_DEBUG, "--------------------------------------------------------------------------------" USBI_LOG_LINE_END);
+ usbi_log_str(LIBUSB_LOG_LEVEL_DEBUG, "[timestamp] [threadID] facility level [function call] <message>" USBI_LOG_LINE_END);
+ usbi_log_str(LIBUSB_LOG_LEVEL_DEBUG, "--------------------------------------------------------------------------------" USBI_LOG_LINE_END);
}
if (now.tv_nsec < timestamp_origin.tv_nsec) {
now.tv_sec--;
@@ -2391,20 +2445,20 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
now.tv_nsec -= timestamp_origin.tv_nsec;
switch (level) {
- case LIBUSB_LOG_LEVEL_INFO:
- prefix = "info";
+ case LIBUSB_LOG_LEVEL_NONE:
+ return;
+ case LIBUSB_LOG_LEVEL_ERROR:
+ prefix = "error";
break;
case LIBUSB_LOG_LEVEL_WARNING:
prefix = "warning";
break;
- case LIBUSB_LOG_LEVEL_ERROR:
- prefix = "error";
+ case LIBUSB_LOG_LEVEL_INFO:
+ prefix = "info";
break;
case LIBUSB_LOG_LEVEL_DEBUG:
prefix = "debug";
break;
- case LIBUSB_LOG_LEVEL_NONE:
- return;
default:
prefix = "unknown";
break;
@@ -2439,7 +2493,7 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
}
strcpy(buf + header_len + text_len, USBI_LOG_LINE_END);
- usbi_log_str(ctx, level, buf);
+ usbi_log_str(level, buf);
}
void usbi_log(struct libusb_context *ctx, enum libusb_log_level level,
@@ -2452,6 +2506,8 @@ void usbi_log(struct libusb_context *ctx, enum libusb_log_level level,
va_end (args);
}
+#endif /* ENABLE_LOGGING */
+
/** \ingroup libusb_misc
* Returns a constant NULL-terminated string with the ASCII name of a libusb
* error or transfer status code. The caller must not free() the returned
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/descriptor.c b/vendor/github.com/karalabe/usb/libusb/libusb/descriptor.c
index 4c9435fff..74d6de557 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/descriptor.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/descriptor.c
@@ -333,7 +333,7 @@ static int parse_interface(libusb_context *ctx,
goto err;
if (r == 0) {
ifp->bNumEndpoints = (uint8_t)i;
- break;;
+ break;
}
buffer += r;
@@ -513,7 +513,7 @@ int usbi_device_cache_descriptor(libusb_device *dev)
{
int r, host_endian = 0;
- r = usbi_backend->get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor,
+ r = usbi_backend.get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor,
&host_endian);
if (r < 0)
return r;
@@ -572,7 +572,7 @@ int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev,
int host_endian = 0;
int r;
- r = usbi_backend->get_active_config_descriptor(dev, tmp,
+ r = usbi_backend.get_active_config_descriptor(dev, tmp,
LIBUSB_DT_CONFIG_SIZE, &host_endian);
if (r < 0)
return r;
@@ -587,7 +587,7 @@ int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev,
if (!buf)
return LIBUSB_ERROR_NO_MEM;
- r = usbi_backend->get_active_config_descriptor(dev, buf,
+ r = usbi_backend.get_active_config_descriptor(dev, buf,
_config.wTotalLength, &host_endian);
if (r >= 0)
r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config);
@@ -625,7 +625,7 @@ int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
if (config_index >= dev->num_configurations)
return LIBUSB_ERROR_NOT_FOUND;
- r = usbi_backend->get_config_descriptor(dev, config_index, tmp,
+ r = usbi_backend.get_config_descriptor(dev, config_index, tmp,
LIBUSB_DT_CONFIG_SIZE, &host_endian);
if (r < 0)
return r;
@@ -640,7 +640,7 @@ int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
if (!buf)
return LIBUSB_ERROR_NO_MEM;
- r = usbi_backend->get_config_descriptor(dev, config_index, buf,
+ r = usbi_backend.get_config_descriptor(dev, config_index, buf,
_config.wTotalLength, &host_endian);
if (r >= 0)
r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config);
@@ -663,7 +663,7 @@ int usbi_get_config_index_by_value(struct libusb_device *dev,
for (i = 0; i < dev->num_configurations; i++) {
unsigned char tmp[6];
int host_endian;
- int r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp),
+ int r = usbi_backend.get_config_descriptor(dev, i, tmp, sizeof(tmp),
&host_endian);
if (r < 0) {
*idx = -1;
@@ -702,8 +702,8 @@ int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev,
int r, idx, host_endian;
unsigned char *buf = NULL;
- if (usbi_backend->get_config_descriptor_by_value) {
- r = usbi_backend->get_config_descriptor_by_value(dev,
+ if (usbi_backend.get_config_descriptor_by_value) {
+ r = usbi_backend.get_config_descriptor_by_value(dev,
bConfigurationValue, &buf, &host_endian);
if (r < 0)
return r;
@@ -1176,7 +1176,8 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_ha
if (tbuf[0] > r)
return LIBUSB_ERROR_IO;
- for (di = 0, si = 2; si < tbuf[0]; si += 2) {
+ di = 0;
+ for (si = 2; si < tbuf[0]; si += 2) {
if (di >= (length - 1))
break;
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.c b/vendor/github.com/karalabe/usb/libusb/libusb/hotplug.c
index bbfd6e79a..a4320bc42 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/hotplug.c
@@ -154,36 +154,30 @@ int main (void) {
\endcode
*/
-static int usbi_hotplug_match_cb (struct libusb_context *ctx,
+static int usbi_hotplug_match_cb(struct libusb_context *ctx,
struct libusb_device *dev, libusb_hotplug_event event,
struct libusb_hotplug_callback *hotplug_cb)
{
- /* Handle lazy deregistration of callback */
- if (hotplug_cb->needs_free) {
- /* Free callback */
- return 1;
- }
-
- if (!(hotplug_cb->events & event)) {
+ if (!(hotplug_cb->flags & event)) {
return 0;
}
- if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->vendor_id &&
+ if ((hotplug_cb->flags & USBI_HOTPLUG_VENDOR_ID_VALID) &&
hotplug_cb->vendor_id != dev->device_descriptor.idVendor) {
return 0;
}
- if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->product_id &&
+ if ((hotplug_cb->flags & USBI_HOTPLUG_PRODUCT_ID_VALID) &&
hotplug_cb->product_id != dev->device_descriptor.idProduct) {
return 0;
}
- if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->dev_class &&
+ if ((hotplug_cb->flags & USBI_HOTPLUG_DEV_CLASS_VALID) &&
hotplug_cb->dev_class != dev->device_descriptor.bDeviceClass) {
return 0;
}
- return hotplug_cb->cb (ctx, dev, event, hotplug_cb->user_data);
+ return hotplug_cb->cb(ctx, dev, event, hotplug_cb->user_data);
}
void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
@@ -195,8 +189,13 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
+ if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE) {
+ /* process deregistration in usbi_hotplug_deregister() */
+ continue;
+ }
+
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
- ret = usbi_hotplug_match_cb (ctx, dev, event, hotplug_cb);
+ ret = usbi_hotplug_match_cb(ctx, dev, event, hotplug_cb);
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
if (ret) {
@@ -206,15 +205,13 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
}
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
-
- /* the backend is expected to call the callback for each active transfer */
}
void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
libusb_hotplug_event event)
{
int pending_events;
- libusb_hotplug_message *message = calloc(1, sizeof(*message));
+ struct libusb_hotplug_message *message = calloc(1, sizeof(*message));
if (!message) {
usbi_err(ctx, "error allocating hotplug message");
@@ -240,59 +237,70 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
libusb_hotplug_callback_fn cb_fn, void *user_data,
libusb_hotplug_callback_handle *callback_handle)
{
- libusb_hotplug_callback *new_callback;
- static int handle_id = 1;
-
- /* check for hotplug support */
- if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
+ struct libusb_hotplug_callback *new_callback;
/* check for sane values */
- if ((LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) ||
+ if ((!events || (~(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) & events)) ||
+ (flags && (~LIBUSB_HOTPLUG_ENUMERATE & flags)) ||
+ (LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) ||
(LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) ||
(LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) ||
!cb_fn) {
return LIBUSB_ERROR_INVALID_PARAM;
}
+ /* check for hotplug support */
+ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ }
+
USBI_GET_CONTEXT(ctx);
- new_callback = (libusb_hotplug_callback *)calloc(1, sizeof (*new_callback));
+ new_callback = calloc(1, sizeof(*new_callback));
if (!new_callback) {
return LIBUSB_ERROR_NO_MEM;
}
- new_callback->ctx = ctx;
- new_callback->vendor_id = vendor_id;
- new_callback->product_id = product_id;
- new_callback->dev_class = dev_class;
- new_callback->flags = flags;
- new_callback->events = events;
+ new_callback->flags = (uint8_t)events;
+ if (LIBUSB_HOTPLUG_MATCH_ANY != vendor_id) {
+ new_callback->flags |= USBI_HOTPLUG_VENDOR_ID_VALID;
+ new_callback->vendor_id = (uint16_t)vendor_id;
+ }
+ if (LIBUSB_HOTPLUG_MATCH_ANY != product_id) {
+ new_callback->flags |= USBI_HOTPLUG_PRODUCT_ID_VALID;
+ new_callback->product_id = (uint16_t)product_id;
+ }
+ if (LIBUSB_HOTPLUG_MATCH_ANY != dev_class) {
+ new_callback->flags |= USBI_HOTPLUG_DEV_CLASS_VALID;
+ new_callback->dev_class = (uint8_t)dev_class;
+ }
new_callback->cb = cb_fn;
new_callback->user_data = user_data;
- new_callback->needs_free = 0;
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
- /* protect the handle by the context hotplug lock. it doesn't matter if the same handle
- * is used for different contexts only that the handle is unique for this context */
- new_callback->handle = handle_id++;
+ /* protect the handle by the context hotplug lock */
+ new_callback->handle = ctx->next_hotplug_cb_handle++;
+
+ /* handle the unlikely case of overflow */
+ if (ctx->next_hotplug_cb_handle < 0)
+ ctx->next_hotplug_cb_handle = 1;
list_add(&new_callback->list, &ctx->hotplug_cbs);
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
+ usbi_dbg("new hotplug cb %p with handle %d", new_callback, new_callback->handle);
- if (flags & LIBUSB_HOTPLUG_ENUMERATE) {
- int i, len;
+ if ((flags & LIBUSB_HOTPLUG_ENUMERATE) && (events & LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)) {
+ ssize_t i, len;
struct libusb_device **devs;
- len = (int) libusb_get_device_list(ctx, &devs);
+ len = libusb_get_device_list(ctx, &devs);
if (len < 0) {
libusb_hotplug_deregister_callback(ctx,
new_callback->handle);
- return len;
+ return (int)len;
}
for (i = 0; i < len; i++) {
@@ -311,10 +319,11 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
return LIBUSB_SUCCESS;
}
-void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx,
+void API_EXPORTED libusb_hotplug_deregister_callback(struct libusb_context *ctx,
libusb_hotplug_callback_handle callback_handle)
{
struct libusb_hotplug_callback *hotplug_cb;
+ int deregistered = 0;
/* check for hotplug support */
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
@@ -323,28 +332,42 @@ void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx
USBI_GET_CONTEXT(ctx);
+ usbi_dbg("deregister hotplug cb %d", callback_handle);
+
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
- list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list,
- struct libusb_hotplug_callback) {
+ list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
if (callback_handle == hotplug_cb->handle) {
/* Mark this callback for deregistration */
- hotplug_cb->needs_free = 1;
+ hotplug_cb->flags |= USBI_HOTPLUG_NEEDS_FREE;
+ deregistered = 1;
}
}
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
- usbi_hotplug_notification(ctx, NULL, 0);
+ if (deregistered) {
+ int pending_events;
+
+ usbi_mutex_lock(&ctx->event_data_lock);
+ pending_events = usbi_pending_events(ctx);
+ ctx->event_flags |= USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
+ if (!pending_events)
+ usbi_signal_event(ctx);
+ usbi_mutex_unlock(&ctx->event_data_lock);
+ }
}
-void usbi_hotplug_deregister_all(struct libusb_context *ctx) {
+void usbi_hotplug_deregister(struct libusb_context *ctx, int forced)
+{
struct libusb_hotplug_callback *hotplug_cb, *next;
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
- list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list,
- struct libusb_hotplug_callback) {
- list_del(&hotplug_cb->list);
- free(hotplug_cb);
+ list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
+ if (forced || (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE)) {
+ usbi_dbg("freeing hotplug cb %p with handle %d", hotplug_cb,
+ hotplug_cb->handle);
+ list_del(&hotplug_cb->list);
+ free(hotplug_cb);
+ }
}
-
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.h b/vendor/github.com/karalabe/usb/libusb/libusb/hotplug.h
index 2bec81b06..dbadbcb93 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/hotplug.h
@@ -19,12 +19,34 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#if !defined(USBI_HOTPLUG_H)
+#ifndef USBI_HOTPLUG_H
#define USBI_HOTPLUG_H
-#ifndef LIBUSBI_H
#include "libusbi.h"
-#endif
+
+enum usbi_hotplug_flags {
+ /* This callback is interested in device arrivals */
+ USBI_HOTPLUG_DEVICE_ARRIVED = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
+
+ /* This callback is interested in device removals */
+ USBI_HOTPLUG_DEVICE_LEFT = LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
+
+ /* IMPORTANT: The values for the below entries must start *after*
+ * the highest value of the above entries!!!
+ */
+
+ /* The vendor_id field is valid for matching */
+ USBI_HOTPLUG_VENDOR_ID_VALID = (1 << 3),
+
+ /* The product_id field is valid for matching */
+ USBI_HOTPLUG_PRODUCT_ID_VALID = (1 << 4),
+
+ /* The dev_class field is valid for matching */
+ USBI_HOTPLUG_DEV_CLASS_VALID = (1 << 5),
+
+ /* This callback has been unregistered and needs to be freed */
+ USBI_HOTPLUG_NEEDS_FREE = (1 << 6),
+};
/** \ingroup hotplug
* The hotplug callback structure. The user populates this structure with
@@ -32,23 +54,17 @@
* to receive notification of hotplug events.
*/
struct libusb_hotplug_callback {
- /** Context this callback is associated with */
- struct libusb_context *ctx;
-
- /** Vendor ID to match or LIBUSB_HOTPLUG_MATCH_ANY */
- int vendor_id;
-
- /** Product ID to match or LIBUSB_HOTPLUG_MATCH_ANY */
- int product_id;
+ /** Flags that control how this callback behaves */
+ uint8_t flags;
- /** Device class to match or LIBUSB_HOTPLUG_MATCH_ANY */
- int dev_class;
+ /** Vendor ID to match (if flags says this is valid) */
+ uint16_t vendor_id;
- /** Hotplug callback flags */
- libusb_hotplug_flag flags;
+ /** Product ID to match (if flags says this is valid) */
+ uint16_t product_id;
- /** Event(s) that will trigger this callback */
- libusb_hotplug_event events;
+ /** Device class to match (if flags says this is valid) */
+ uint8_t dev_class;
/** Callback function to invoke for matching event/device */
libusb_hotplug_callback_fn cb;
@@ -59,15 +75,10 @@ struct libusb_hotplug_callback {
/** User data that will be passed to the callback function */
void *user_data;
- /** Callback is marked for deletion */
- int needs_free;
-
/** List this callback is registered in (ctx->hotplug_cbs) */
struct list_head list;
};
-typedef struct libusb_hotplug_callback libusb_hotplug_callback;
-
struct libusb_hotplug_message {
/** The hotplug event that occurred */
libusb_hotplug_event event;
@@ -79,9 +90,7 @@ struct libusb_hotplug_message {
struct list_head list;
};
-typedef struct libusb_hotplug_message libusb_hotplug_message;
-
-void usbi_hotplug_deregister_all(struct libusb_context *ctx);
+void usbi_hotplug_deregister(struct libusb_context *ctx, int forced);
void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
libusb_hotplug_event event);
void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/io.c b/vendor/github.com/karalabe/usb/libusb/libusb/io.c
index eb1eabf1c..a03bfaae1 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/io.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/io.c
@@ -1144,8 +1144,8 @@ int usbi_io_init(struct libusb_context *ctx)
goto err_close_pipe;
#ifdef USBI_TIMERFD_AVAILABLE
- ctx->timerfd = timerfd_create(usbi_backend->get_timerfd_clockid(),
- TFD_NONBLOCK);
+ ctx->timerfd = timerfd_create(usbi_backend.get_timerfd_clockid(),
+ TFD_NONBLOCK | TFD_CLOEXEC);
if (ctx->timerfd >= 0) {
usbi_dbg("using timerfd for timeouts");
r = usbi_add_pollfd(ctx, ctx->timerfd, POLLIN);
@@ -1205,10 +1205,12 @@ static int calculate_timeout(struct usbi_transfer *transfer)
unsigned int timeout =
USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout;
- if (!timeout)
+ if (!timeout) {
+ timerclear(&transfer->timeout);
return 0;
+ }
- r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &current_time);
+ r = usbi_backend.clock_gettime(USBI_CLOCK_MONOTONIC, &current_time);
if (r < 0) {
usbi_err(ITRANSFER_CTX(transfer),
"failed to read monotonic clock, errno=%d", errno);
@@ -1255,7 +1257,7 @@ struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(
int iso_packets)
{
struct libusb_transfer *transfer;
- size_t os_alloc_size = usbi_backend->transfer_priv_size;
+ size_t os_alloc_size = usbi_backend.transfer_priv_size;
size_t alloc_size = sizeof(struct usbi_transfer)
+ sizeof(struct libusb_transfer)
+ (sizeof(struct libusb_iso_packet_descriptor) * iso_packets)
@@ -1526,7 +1528,7 @@ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer)
*/
usbi_mutex_unlock(&ctx->flying_transfers_lock);
- r = usbi_backend->submit_transfer(itransfer);
+ r = usbi_backend.submit_transfer(itransfer);
if (r == LIBUSB_SUCCESS) {
itransfer->state_flags |= USBI_TRANSFER_IN_FLIGHT;
/* keep a reference to this device */
@@ -1567,7 +1569,7 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer)
r = LIBUSB_ERROR_NOT_FOUND;
goto out;
}
- r = usbi_backend->cancel_transfer(itransfer);
+ r = usbi_backend.cancel_transfer(itransfer);
if (r < 0) {
if (r != LIBUSB_ERROR_NOT_FOUND &&
r != LIBUSB_ERROR_NO_DEVICE)
@@ -2004,7 +2006,7 @@ static int handle_timeouts_locked(struct libusb_context *ctx)
return 0;
/* get current time */
- r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &systime_ts);
+ r = usbi_backend.clock_gettime(USBI_CLOCK_MONOTONIC, &systime_ts);
if (r < 0)
return r;
@@ -2077,7 +2079,6 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
struct pollfd *fds = NULL;
int i = -1;
int timeout_ms;
- int special_event;
/* prevent attempts to recursively handle events (e.g. calling into
* libusb_handle_events() from within a hotplug or transfer callback) */
@@ -2146,32 +2147,30 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
if (tv->tv_usec % 1000)
timeout_ms++;
-redo_poll:
usbi_dbg("poll() %d fds with timeout in %dms", nfds, timeout_ms);
r = usbi_poll(fds, nfds, timeout_ms);
usbi_dbg("poll() returned %d", r);
if (r == 0) {
r = handle_timeouts(ctx);
goto done;
- }
- else if (r == -1 && errno == EINTR) {
+ } else if (r == -1 && errno == EINTR) {
r = LIBUSB_ERROR_INTERRUPTED;
goto done;
- }
- else if (r < 0) {
+ } else if (r < 0) {
usbi_err(ctx, "poll failed %d err=%d", r, errno);
r = LIBUSB_ERROR_IO;
goto done;
}
- special_event = 0;
-
/* fds[0] is always the event pipe */
if (fds[0].revents) {
- libusb_hotplug_message *message = NULL;
+ struct list_head hotplug_msgs;
struct usbi_transfer *itransfer;
+ int hotplug_cb_deregistered = 0;
int ret = 0;
+ list_init(&hotplug_msgs);
+
usbi_dbg("caught a fish on the event pipe");
/* take the the event data lock while processing events */
@@ -2186,6 +2185,12 @@ redo_poll:
ctx->event_flags &= ~USBI_EVENT_USER_INTERRUPT;
}
+ if (ctx->event_flags & USBI_EVENT_HOTPLUG_CB_DEREGISTERED) {
+ usbi_dbg("someone unregistered a hotplug cb");
+ ctx->event_flags &= ~USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
+ hotplug_cb_deregistered = 1;
+ }
+
/* check if someone is closing a device */
if (ctx->device_close)
usbi_dbg("someone is closing a device");
@@ -2193,9 +2198,7 @@ redo_poll:
/* check for any pending hotplug messages */
if (!list_empty(&ctx->hotplug_msgs)) {
usbi_dbg("hotplug message received");
- special_event = 1;
- message = list_first_entry(&ctx->hotplug_msgs, libusb_hotplug_message, list);
- list_del(&message->list);
+ list_cut(&hotplug_msgs, &ctx->hotplug_msgs);
}
/* complete any pending transfers */
@@ -2203,7 +2206,7 @@ redo_poll:
itransfer = list_first_entry(&ctx->completed_transfers, struct usbi_transfer, completed_list);
list_del(&itransfer->completed_list);
usbi_mutex_unlock(&ctx->event_data_lock);
- ret = usbi_backend->handle_transfer_completion(itransfer);
+ ret = usbi_backend.handle_transfer_completion(itransfer);
if (ret)
usbi_err(ctx, "backend handle_transfer_completion failed with error %d", ret);
usbi_mutex_lock(&ctx->event_data_lock);
@@ -2215,14 +2218,21 @@ redo_poll:
usbi_mutex_unlock(&ctx->event_data_lock);
- /* process the hotplug message, if any */
- if (message) {
+ if (hotplug_cb_deregistered)
+ usbi_hotplug_deregister(ctx, 0);
+
+ /* process the hotplug messages, if any */
+ while (!list_empty(&hotplug_msgs)) {
+ struct libusb_hotplug_message *message =
+ list_first_entry(&hotplug_msgs, struct libusb_hotplug_message, list);
+
usbi_hotplug_match(ctx, message->device, message->event);
/* the device left, dereference the device */
if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == message->event)
libusb_unref_device(message->device);
+ list_del(&message->list);
free(message);
}
@@ -2233,7 +2243,7 @@ redo_poll:
}
if (0 == --r)
- goto handled;
+ goto done;
}
#ifdef USBI_TIMERFD_AVAILABLE
@@ -2242,7 +2252,6 @@ redo_poll:
/* timerfd indicates that a timeout has expired */
int ret;
usbi_dbg("timerfd triggered");
- special_event = 1;
ret = handle_timerfd_trigger(ctx);
if (ret < 0) {
@@ -2252,20 +2261,14 @@ redo_poll:
}
if (0 == --r)
- goto handled;
+ goto done;
}
#endif
- r = usbi_backend->handle_events(ctx, fds + internal_nfds, nfds - internal_nfds, r);
+ r = usbi_backend.handle_events(ctx, fds + internal_nfds, nfds - internal_nfds, r);
if (r)
usbi_err(ctx, "backend handle_events failed with error %d", r);
-handled:
- if (r == 0 && special_event) {
- timeout_ms = 0;
- goto redo_poll;
- }
-
done:
usbi_end_event_handling(ctx);
return r;
@@ -2583,7 +2586,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
return 0;
}
- r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &cur_ts);
+ r = usbi_backend.clock_gettime(USBI_CLOCK_MONOTONIC, &cur_ts);
if (r < 0) {
usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno);
return 0;
@@ -2811,7 +2814,7 @@ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle)
USBI_TRANSFER_TO_LIBUSB_TRANSFER(to_cancel));
usbi_mutex_lock(&to_cancel->lock);
- usbi_backend->clear_transfer_priv(to_cancel);
+ usbi_backend.clear_transfer_priv(to_cancel);
usbi_mutex_unlock(&to_cancel->lock);
usbi_handle_transfer_completion(to_cancel, LIBUSB_TRANSFER_NO_DEVICE);
}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/libusb.h b/vendor/github.com/karalabe/usb/libusb/libusb/libusb.h
index c562690f9..430136b2e 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/libusb.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/libusb.h
@@ -54,13 +54,19 @@ typedef unsigned __int32 uint32_t;
#include <sys/types.h>
#endif
-#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__)
+#if defined(__linux__) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__)
#include <sys/time.h>
#endif
#include <time.h>
#include <limits.h>
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#define ZERO_SIZED_ARRAY /* [] - valid C99 code */
+#else
+#define ZERO_SIZED_ARRAY 0 /* [0] - non-standard, but usually working code */
+#endif
+
/* 'interface' might be defined as a macro on Windows, so we need to
* undefine it so as not to break the current libusb API, because
* libusb_config_descriptor has an 'interface' member
@@ -79,6 +85,8 @@ typedef unsigned __int32 uint32_t;
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
#define LIBUSB_DEPRECATED_FOR(f) \
__attribute__((deprecated("Use " #f " instead")))
+#elif __GNUC__ >= 3
+#define LIBUSB_DEPRECATED_FOR(f) __attribute__((deprecated))
#else
#define LIBUSB_DEPRECATED_FOR(f)
#endif /* __GNUC__ */
@@ -141,7 +149,7 @@ typedef unsigned __int32 uint32_t;
* Internally, LIBUSB_API_VERSION is defined as follows:
* (libusb major << 24) | (libusb minor << 16) | (16 bit incremental)
*/
-#define LIBUSB_API_VERSION 0x01000105
+#define LIBUSB_API_VERSION 0x01000106
/* The following is kept for compatibility, but will be deprecated in the future */
#define LIBUSBX_API_VERSION LIBUSB_API_VERSION
@@ -729,13 +737,7 @@ struct libusb_bos_dev_capability_descriptor {
/** Device Capability type */
uint8_t bDevCapabilityType;
/** Device Capability data (bLength - 3 bytes) */
- uint8_t dev_capability_data
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
- ;
+ uint8_t dev_capability_data[ZERO_SIZED_ARRAY];
};
/** \ingroup libusb_desc
@@ -760,13 +762,7 @@ struct libusb_bos_descriptor {
uint8_t bNumDeviceCaps;
/** bNumDeviceCap Device Capability Descriptors */
- struct libusb_bos_dev_capability_descriptor *dev_capability
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
- ;
+ struct libusb_bos_dev_capability_descriptor *dev_capability[ZERO_SIZED_ARRAY];
};
/** \ingroup libusb_desc
@@ -927,7 +923,7 @@ struct libusb_version {
* sessions allows for your program to use two libraries (or dynamically
* load two modules) which both independently use libusb. This will prevent
* interference between the individual libusb users - for example
- * libusb_set_debug() will not affect the other user of the library, and
+ * libusb_set_option() will not affect the other user of the library, and
* libusb_exit() will not destroy resources that the other user is still
* using.
*
@@ -987,6 +983,9 @@ enum libusb_speed {
/** The device is operating at super speed (5000MBit/s). */
LIBUSB_SPEED_SUPER = 4,
+
+ /** The device is operating at super speed plus (10000MBit/s). */
+ LIBUSB_SPEED_SUPER_PLUS = 5,
};
/** \ingroup libusb_dev
@@ -1256,13 +1255,7 @@ struct libusb_transfer {
int num_iso_packets;
/** Isochronous packet descriptors, for isochronous transfers only. */
- struct libusb_iso_packet_descriptor iso_packet_desc
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
- ;
+ struct libusb_iso_packet_descriptor iso_packet_desc[ZERO_SIZED_ARRAY];
};
/** \ingroup libusb_misc
@@ -1290,21 +1283,20 @@ enum libusb_capability {
* - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default)
* - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr
* - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr
- * - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stdout, warning
- * and error messages are printed to stderr
- * - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stdout,
- * warnings and errors to stderr
+ * - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stderr
+ * - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stderr
*/
enum libusb_log_level {
LIBUSB_LOG_LEVEL_NONE = 0,
- LIBUSB_LOG_LEVEL_ERROR,
- LIBUSB_LOG_LEVEL_WARNING,
- LIBUSB_LOG_LEVEL_INFO,
- LIBUSB_LOG_LEVEL_DEBUG,
+ LIBUSB_LOG_LEVEL_ERROR = 1,
+ LIBUSB_LOG_LEVEL_WARNING = 2,
+ LIBUSB_LOG_LEVEL_INFO = 3,
+ LIBUSB_LOG_LEVEL_DEBUG = 4,
};
int LIBUSB_CALL libusb_init(libusb_context **ctx);
void LIBUSB_CALL libusb_exit(libusb_context *ctx);
+LIBUSB_DEPRECATED_FOR(libusb_set_option)
void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level);
const struct libusb_version * LIBUSB_CALL libusb_get_version(void);
int LIBUSB_CALL libusb_has_capability(uint32_t capability);
@@ -2001,6 +1993,45 @@ int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx,
void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx,
libusb_hotplug_callback_handle callback_handle);
+/** \ingroup libusb_lib
+ * Available option values for libusb_set_option().
+ */
+enum libusb_option {
+ /** Set the log message verbosity.
+ *
+ * The default level is LIBUSB_LOG_LEVEL_NONE, which means no messages are ever
+ * printed. If you choose to increase the message verbosity level, ensure
+ * that your application does not close the stderr file descriptor.
+ *
+ * You are advised to use level LIBUSB_LOG_LEVEL_WARNING. libusb is conservative
+ * with its message logging and most of the time, will only log messages that
+ * explain error conditions and other oddities. This will help you debug
+ * your software.
+ *
+ * If the LIBUSB_DEBUG environment variable was set when libusb was
+ * initialized, this function does nothing: the message verbosity is fixed
+ * to the value in the environment variable.
+ *
+ * If libusb was compiled without any message logging, this function does
+ * nothing: you'll never get any messages.
+ *
+ * If libusb was compiled with verbose debug message logging, this function
+ * does nothing: you'll always get messages from all levels.
+ */
+ LIBUSB_OPTION_LOG_LEVEL,
+
+ /** Use the UsbDk backend for a specific context, if available.
+ *
+ * This option should be set immediately after calling libusb_init(), otherwise
+ * unspecified behavior may occur.
+ *
+ * Only valid on Windows.
+ */
+ LIBUSB_OPTION_USE_USBDK,
+};
+
+int LIBUSB_CALL libusb_set_option(libusb_context *ctx, enum libusb_option option, ...);
+
#ifdef __cplusplus
}
#endif
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/libusbi.h b/vendor/github.com/karalabe/usb/libusb/libusb/libusbi.h
index 752e39887..31d6ce98d 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/libusbi.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/libusbi.h
@@ -39,6 +39,20 @@
#include "libusb.h"
#include "version.h"
+/* Attribute to ensure that a structure member is aligned to a natural
+ * pointer alignment. Used for os_priv member. */
+#if defined(_MSC_VER)
+#if defined(_WIN64)
+#define PTR_ALIGNED __declspec(align(8))
+#else
+#define PTR_ALIGNED __declspec(align(4))
+#endif
+#elif defined(__GNUC__)
+#define PTR_ALIGNED __attribute__((aligned(sizeof(void *))))
+#else
+#define PTR_ALIGNED
+#endif
+
/* Inside the libusb code, mark all public functions as follows:
* return_type API_EXPORTED function_name(params) { ... }
* But if the function returns a pointer, mark it as follows:
@@ -139,6 +153,19 @@ static inline void list_del(struct list_head *entry)
entry->next = entry->prev = NULL;
}
+static inline void list_cut(struct list_head *list, struct list_head *head)
+{
+ if (list_empty(head))
+ return;
+
+ list->next = head->next;
+ list->next->prev = list;
+ list->prev = head->prev;
+ list->prev->next = list;
+
+ list_init(head);
+}
+
static inline void *usbi_reallocf(void *ptr, size_t size)
{
void *ret = realloc(ptr, size);
@@ -151,6 +178,9 @@ static inline void *usbi_reallocf(void *ptr, size_t size)
const typeof( ((type *)0)->member ) *mptr = (ptr); \
(type *)( (char *)mptr - offsetof(type,member) );})
+#ifndef CLAMP
+#define CLAMP(val, min, max) ((val) < (min) ? (min) : ((val) > (max) ? (max) : (val)))
+#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
@@ -175,29 +205,33 @@ static inline void *usbi_reallocf(void *ptr, size_t size)
} while (0)
#endif
+#ifdef ENABLE_LOGGING
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define snprintf usbi_snprintf
+#define vsnprintf usbi_vsnprintf
+int usbi_snprintf(char *dst, size_t size, const char *format, ...);
+int usbi_vsnprintf(char *dst, size_t size, const char *format, va_list ap);
+#define LIBUSB_PRINTF_WIN32
+#endif /* defined(_MSC_VER) && (_MSC_VER < 1900) */
+
void usbi_log(struct libusb_context *ctx, enum libusb_log_level level,
const char *function, const char *format, ...);
void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
const char *function, const char *format, va_list args);
-#if !defined(_MSC_VER) || _MSC_VER >= 1400
+#if !defined(_MSC_VER) || (_MSC_VER >= 1400)
-#ifdef ENABLE_LOGGING
#define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__)
-#define usbi_dbg(...) _usbi_log(NULL, LIBUSB_LOG_LEVEL_DEBUG, __VA_ARGS__)
-#else
-#define _usbi_log(ctx, level, ...) do { (void)(ctx); } while(0)
-#define usbi_dbg(...) do {} while(0)
-#endif
-#define usbi_info(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_INFO, __VA_ARGS__)
-#define usbi_warn(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_WARNING, __VA_ARGS__)
#define usbi_err(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_ERROR, __VA_ARGS__)
+#define usbi_warn(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_WARNING, __VA_ARGS__)
+#define usbi_info(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_INFO, __VA_ARGS__)
+#define usbi_dbg(...) _usbi_log(NULL, LIBUSB_LOG_LEVEL_DEBUG, __VA_ARGS__)
-#else /* !defined(_MSC_VER) || _MSC_VER >= 1400 */
+#else /* !defined(_MSC_VER) || (_MSC_VER >= 1400) */
-#ifdef ENABLE_LOGGING
#define LOG_BODY(ctxt, level) \
{ \
va_list args; \
@@ -205,24 +239,26 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
usbi_log_v(ctxt, level, "", format, args); \
va_end(args); \
}
-#else
-#define LOG_BODY(ctxt, level) \
-{ \
- (void)(ctxt); \
-}
-#endif
-static inline void usbi_info(struct libusb_context *ctx, const char *format, ...)
- LOG_BODY(ctx, LIBUSB_LOG_LEVEL_INFO)
-static inline void usbi_warn(struct libusb_context *ctx, const char *format, ...)
- LOG_BODY(ctx, LIBUSB_LOG_LEVEL_WARNING)
static inline void usbi_err(struct libusb_context *ctx, const char *format, ...)
LOG_BODY(ctx, LIBUSB_LOG_LEVEL_ERROR)
-
+static inline void usbi_warn(struct libusb_context *ctx, const char *format, ...)
+ LOG_BODY(ctx, LIBUSB_LOG_LEVEL_WARNING)
+static inline void usbi_info(struct libusb_context *ctx, const char *format, ...)
+ LOG_BODY(ctx, LIBUSB_LOG_LEVEL_INFO)
static inline void usbi_dbg(const char *format, ...)
LOG_BODY(NULL, LIBUSB_LOG_LEVEL_DEBUG)
-#endif /* !defined(_MSC_VER) || _MSC_VER >= 1400 */
+#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1400) */
+
+#else /* ENABLE_LOGGING */
+
+#define usbi_err(ctx, ...) do { (void)ctx; } while (0)
+#define usbi_warn(ctx, ...) do { (void)ctx; } while (0)
+#define usbi_info(ctx, ...) do { (void)ctx; } while (0)
+#define usbi_dbg(...) do {} while (0)
+
+#endif /* ENABLE_LOGGING */
#define USBI_GET_CONTEXT(ctx) \
do { \
@@ -254,8 +290,10 @@ extern struct libusb_context *usbi_default_context;
struct pollfd;
struct libusb_context {
- int debug;
+#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
+ enum libusb_log_level debug;
int debug_fixed;
+#endif
/* internal event pipe, used for signalling occurrence of an internal event. */
int event_pipe[2];
@@ -270,6 +308,7 @@ struct libusb_context {
/* A list of registered hotplug callbacks */
struct list_head hotplug_cbs;
+ libusb_hotplug_callback_handle next_hotplug_cb_handle;
usbi_mutex_t hotplug_cbs_lock;
/* this is a list of in-flight transfer handles, sorted by timeout
@@ -331,6 +370,8 @@ struct libusb_context {
#endif
struct list_head list;
+
+ PTR_ALIGNED unsigned char os_priv[ZERO_SIZED_ARRAY];
};
enum usbi_event_flags {
@@ -339,6 +380,9 @@ enum usbi_event_flags {
/* The user has interrupted the event handler */
USBI_EVENT_USER_INTERRUPT = 1 << 1,
+
+ /* A hotplug callback deregistration is pending */
+ USBI_EVENT_HOTPLUG_CB_DEREGISTERED = 1 << 2,
};
/* Macros for managing event handling state */
@@ -383,17 +427,7 @@ struct libusb_device {
struct libusb_device_descriptor device_descriptor;
int attached;
- unsigned char os_priv
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
-#if defined(OS_SUNOS)
- __attribute__ ((aligned (8)));
-#else
- ;
-#endif
+ PTR_ALIGNED unsigned char os_priv[ZERO_SIZED_ARRAY];
};
struct libusb_device_handle {
@@ -404,17 +438,8 @@ struct libusb_device_handle {
struct list_head list;
struct libusb_device *dev;
int auto_detach_kernel_driver;
- unsigned char os_priv
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
-#if defined(OS_SUNOS)
- __attribute__ ((aligned (8)));
-#else
- ;
-#endif
+
+ PTR_ALIGNED unsigned char os_priv[ZERO_SIZED_ARRAY];
};
enum {
@@ -540,14 +565,6 @@ int usbi_clear_event(struct libusb_context *ctx);
#include "os/poll_windows.h"
#endif
-#if defined(_MSC_VER) && (_MSC_VER < 1900)
-#define snprintf usbi_snprintf
-#define vsnprintf usbi_vsnprintf
-int usbi_snprintf(char *dst, size_t size, const char *format, ...);
-int usbi_vsnprintf(char *dst, size_t size, const char *format, va_list ap);
-#define LIBUSB_PRINTF_WIN32
-#endif
-
struct usbi_pollfd {
/* must come first */
struct libusb_pollfd pollfd;
@@ -568,13 +585,7 @@ void usbi_remove_pollfd(struct libusb_context *ctx, int fd);
struct discovered_devs {
size_t len;
size_t capacity;
- struct libusb_device *devices
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
- ;
+ struct libusb_device *devices[ZERO_SIZED_ARRAY];
};
struct discovered_devs *discovered_devs_append(
@@ -607,7 +618,17 @@ struct usbi_os_backend {
*
* This function is called when the user deinitializes the library.
*/
- void (*exit)(void);
+ void (*exit)(struct libusb_context *ctx);
+
+ /* Set a backend-specific option. Optional.
+ *
+ * This function is called when the user calls libusb_set_option() and
+ * the option is not handled by the core library.
+ *
+ * Return 0 on success, or a LIBUSB_ERROR code on failure.
+ */
+ int (*set_option)(struct libusb_context *ctx, enum libusb_option option,
+ va_list args);
/* Enumerate all the USB devices on the system, returning them in a list
* of discovered devices.
@@ -1110,6 +1131,11 @@ struct usbi_os_backend {
clockid_t (*get_timerfd_clockid)(void);
#endif
+ /* Number of bytes to reserve for per-context private backend data.
+ * This private data area is accessible through the "os_priv" field of
+ * struct libusb_context. */
+ size_t context_priv_size;
+
/* Number of bytes to reserve for per-device private backend data.
* This private data area is accessible through the "os_priv" field of
* struct libusb_device. */
@@ -1127,17 +1153,7 @@ struct usbi_os_backend {
size_t transfer_priv_size;
};
-extern const struct usbi_os_backend * const usbi_backend;
-
-extern const struct usbi_os_backend linux_usbfs_backend;
-extern const struct usbi_os_backend darwin_backend;
-extern const struct usbi_os_backend openbsd_backend;
-extern const struct usbi_os_backend netbsd_backend;
-extern const struct usbi_os_backend windows_backend;
-extern const struct usbi_os_backend usbdk_backend;
-extern const struct usbi_os_backend wince_backend;
-extern const struct usbi_os_backend haiku_usb_raw_backend;
-extern const struct usbi_os_backend sunos_backend;
+extern const struct usbi_os_backend usbi_backend;
extern struct list_head active_contexts_list;
extern usbi_mutex_static_t active_contexts_lock;
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/darwin_usb.c
index b0219d1b0..35ea1c321 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/darwin_usb.c
@@ -1,7 +1,7 @@
/* -*- Mode: C; indent-tabs-mode:nil -*- */
/*
* darwin backend for libusb 1.0
- * Copyright © 2008-2016 Nathan Hjelm <hjelmn@users.sourceforge.net>
+ * Copyright © 2008-2017 Nathan Hjelm <hjelmn@users.sourceforge.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -36,6 +36,10 @@
#include <mach/mach_host.h>
#include <mach/mach_port.h>
+/* Suppress warnings about the use of the deprecated objc_registerThreadWithCollector
+ * function. Its use is also conditionalized to only older deployment targets. */
+#define OBJC_SILENCE_GC_DEPRECATIONS 1
+
#include <AvailabilityMacros.h>
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 && MAC_OS_X_VERSION_MIN_REQUIRED < 101200
#include <objc/objc-auto.h>
@@ -55,6 +59,14 @@ _Atomic int32_t initCount = ATOMIC_VAR_INIT(0);
#define libusb_darwin_atomic_fetch_add(x, y) (OSAtomicAdd32Barrier(y, x) - y)
static volatile int32_t initCount = 0;
+
+#endif
+
+/* On 10.12 and later, use newly available clock_*() functions */
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
+#define OSX_USE_CLOCK_GETTIME 1
+#else
+#define OSX_USE_CLOCK_GETTIME 0
#endif
#include "darwin_usb.h"
@@ -65,15 +77,17 @@ static pthread_cond_t libusb_darwin_at_cond = PTHREAD_COND_INITIALIZER;
static pthread_once_t darwin_init_once = PTHREAD_ONCE_INIT;
+#if !OSX_USE_CLOCK_GETTIME
static clock_serv_t clock_realtime;
static clock_serv_t clock_monotonic;
+#endif
static CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */
static CFRunLoopSourceRef libusb_darwin_acfls = NULL; /* shutdown signal for event cf loop */
static usbi_mutex_t darwin_cached_devices_lock = PTHREAD_MUTEX_INITIALIZER;
static struct list_head darwin_cached_devices = {&darwin_cached_devices, &darwin_cached_devices};
-static char *darwin_device_class = kIOUSBDeviceClassName;
+static const char *darwin_device_class = kIOUSBDeviceClassName;
#define DARWIN_CACHED_DEVICE(a) ((struct darwin_cached_device *) (((struct darwin_device_priv *)((a)->os_priv))->dev))
@@ -219,20 +233,21 @@ static int usb_setup_device_iterator (io_iterator_t *deviceIterator, UInt32 loca
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
- if (propertyMatchDict) {
- /* there are no unsigned CFNumber types so treat the value as signed. the os seems to do this
- internally (CFNumberType of locationID is 3) */
- CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberSInt32Type, &location);
+ /* there are no unsigned CFNumber types so treat the value as signed. the OS seems to do this
+ internally (CFNumberType of locationID is kCFNumberSInt32Type) */
+ CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberSInt32Type, &location);
+ if (propertyMatchDict && locationCF) {
CFDictionarySetValue (propertyMatchDict, CFSTR(kUSBDevicePropertyLocationID), locationCF);
- /* release our reference to the CFNumber (CFDictionarySetValue retains it) */
- CFRelease (locationCF);
-
CFDictionarySetValue (matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
- /* release out reference to the CFMutableDictionaryRef (CFDictionarySetValue retains it) */
- CFRelease (propertyMatchDict);
}
/* else we can still proceed as long as the caller accounts for the possibility of other devices in the iterator */
+
+ /* release our references as per the Create Rule */
+ if (propertyMatchDict)
+ CFRelease (propertyMatchDict);
+ if (locationCF)
+ CFRelease (locationCF);
}
return IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, deviceIterator);
@@ -300,6 +315,7 @@ static usb_device_t **darwin_device_from_service (io_service_t service)
}
static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) {
+ UNUSED(ptr);
struct libusb_context *ctx;
io_service_t service;
@@ -308,7 +324,7 @@ static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) {
while ((service = IOIteratorNext(add_devices))) {
/* add this device to each active context's device list */
list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
- process_new_device (ctx, service);;
+ process_new_device (ctx, service);
}
IOObjectRelease(service);
@@ -318,6 +334,7 @@ static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) {
}
static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
+ UNUSED(ptr);
struct libusb_device *dev = NULL;
struct libusb_context *ctx;
struct darwin_cached_device *old_device;
@@ -516,7 +533,6 @@ static void darwin_check_version (void) {
}
static int darwin_init(struct libusb_context *ctx) {
- host_name_port_t host_self;
int rc;
rc = pthread_once (&darwin_init_once, darwin_check_version);
@@ -530,12 +546,15 @@ static int darwin_init(struct libusb_context *ctx) {
}
if (libusb_darwin_atomic_fetch_add (&initCount, 1) == 0) {
- /* create the clocks that will be used */
+#if !OSX_USE_CLOCK_GETTIME
+ /* create the clocks that will be used if clock_gettime() is not available */
+ host_name_port_t host_self;
host_self = mach_host_self();
host_get_clock_service(host_self, CALENDAR_CLOCK, &clock_realtime);
host_get_clock_service(host_self, SYSTEM_CLOCK, &clock_monotonic);
mach_port_deallocate(mach_task_self(), host_self);
+#endif
pthread_create (&libusb_darwin_at, NULL, darwin_event_thread_main, ctx);
@@ -548,10 +567,13 @@ static int darwin_init(struct libusb_context *ctx) {
return rc;
}
-static void darwin_exit (void) {
+static void darwin_exit (struct libusb_context *ctx) {
+ UNUSED(ctx);
if (libusb_darwin_atomic_fetch_add (&initCount, -1) == 1) {
+#if !OSX_USE_CLOCK_GETTIME
mach_port_deallocate(mach_task_self(), clock_realtime);
mach_port_deallocate(mach_task_self(), clock_monotonic);
+#endif
/* stop the event runloop and wait for the thread to terminate. */
CFRunLoopSourceSignal(libusb_darwin_acfls);
@@ -866,14 +888,29 @@ static int get_device_port (io_service_t service, UInt8 *port) {
return ret;
}
+static int get_device_parent_sessionID(io_service_t service, UInt64 *parent_sessionID) {
+ kern_return_t result;
+ io_service_t parent;
+
+ /* Walk up the tree in the IOService plane until we find a parent that has a sessionID */
+ parent = service;
+ while((result = IORegistryEntryGetParentEntry (parent, kIOServicePlane, &parent)) == kIOReturnSuccess) {
+ if (get_ioregistry_value_number (parent, CFSTR("sessionID"), kCFNumberSInt64Type, parent_sessionID)) {
+ /* Success */
+ return 1;
+ }
+ }
+
+ /* We ran out of parents */
+ return 0;
+}
+
static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t service,
struct darwin_cached_device **cached_out) {
struct darwin_cached_device *new_device;
UInt64 sessionID = 0, parent_sessionID = 0;
int ret = LIBUSB_SUCCESS;
usb_device_t **device;
- io_service_t parent;
- kern_return_t result;
UInt8 port = 0;
/* get some info from the io registry */
@@ -884,11 +921,8 @@ static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t ser
usbi_dbg("finding cached device for sessionID 0x%" PRIx64, sessionID);
- result = IORegistryEntryGetParentEntry (service, kIOUSBPlane, &parent);
-
- if (kIOReturnSuccess == result) {
- (void) get_ioregistry_value_number (parent, CFSTR("sessionID"), kCFNumberSInt64Type, &parent_sessionID);
- IOObjectRelease(parent);
+ if (get_device_parent_sessionID(service, &parent_sessionID)) {
+ usbi_dbg("parent sessionID: 0x%" PRIx64, parent_sessionID);
}
usbi_mutex_lock(&darwin_cached_devices_lock);
@@ -1005,9 +1039,12 @@ static int process_new_device (struct libusb_context *ctx, io_service_t service)
case kUSBDeviceSpeedLow: dev->speed = LIBUSB_SPEED_LOW; break;
case kUSBDeviceSpeedFull: dev->speed = LIBUSB_SPEED_FULL; break;
case kUSBDeviceSpeedHigh: dev->speed = LIBUSB_SPEED_HIGH; break;
-#if DeviceVersion >= 500
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
case kUSBDeviceSpeedSuper: dev->speed = LIBUSB_SPEED_SUPER; break;
#endif
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
+ case kUSBDeviceSpeedSuperPlus: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break;
+#endif
default:
usbi_warn (ctx, "Got unknown device speed %d", devSpeed);
}
@@ -1216,9 +1253,9 @@ static int get_endpoints (struct libusb_device_handle *dev_handle, int iface) {
kern_return_t kresult;
- u_int8_t numep, direction, number;
- u_int8_t dont_care1, dont_care3;
- u_int16_t dont_care2;
+ UInt8 numep, direction, number;
+ UInt8 dont_care1, dont_care3;
+ UInt16 dont_care2;
int rc;
usbi_dbg ("building table of endpoints.");
@@ -1965,6 +2002,7 @@ static int darwin_handle_transfer_completion (struct usbi_transfer *itransfer) {
}
static int darwin_clock_gettime(int clk_id, struct timespec *tp) {
+#if !OSX_USE_CLOCK_GETTIME
mach_timespec_t sys_time;
clock_serv_t clock_ref;
@@ -1987,6 +2025,16 @@ static int darwin_clock_gettime(int clk_id, struct timespec *tp) {
tp->tv_nsec = sys_time.tv_nsec;
return 0;
+#else
+ switch (clk_id) {
+ case USBI_CLOCK_MONOTONIC:
+ return clock_gettime(CLOCK_MONOTONIC, tp);
+ case USBI_CLOCK_REALTIME:
+ return clock_gettime(CLOCK_REALTIME, tp);
+ default:
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+#endif
}
#if InterfaceVersion >= 550
@@ -2047,7 +2095,7 @@ static int darwin_free_streams (struct libusb_device_handle *dev_handle, unsigne
}
#endif
-const struct usbi_os_backend darwin_backend = {
+const struct usbi_os_backend usbi_backend = {
.name = "Darwin",
.caps = 0,
.init = darwin_init,
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/darwin_usb.h
index 118043421..474567f6a 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/darwin_usb.h
@@ -28,37 +28,58 @@
#include <IOKit/IOCFPlugIn.h>
/* IOUSBInterfaceInferface */
-#if defined (kIOUSBInterfaceInterfaceID700) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+
+/* New in OS 10.12.0. */
+#if defined (kIOUSBInterfaceInterfaceID800) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
+
+#define usb_interface_t IOUSBInterfaceInterface800
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID800
+#define InterfaceVersion 800
+
+/* New in OS 10.10.0. */
+#elif defined (kIOUSBInterfaceInterfaceID700) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 101000)
#define usb_interface_t IOUSBInterfaceInterface700
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID700
#define InterfaceVersion 700
-#elif defined (kIOUSBInterfaceInterfaceID550) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+/* New in OS 10.9.0. */
+#elif defined (kIOUSBInterfaceInterfaceID650) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
+
+#define usb_interface_t IOUSBInterfaceInterface650
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID650
+#define InterfaceVersion 650
+
+/* New in OS 10.8.2 but can't test deployment target to that granularity, so round up. */
+#elif defined (kIOUSBInterfaceInterfaceID550) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
#define usb_interface_t IOUSBInterfaceInterface550
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID550
#define InterfaceVersion 550
-#elif defined (kIOUSBInterfaceInterfaceID500)
+/* New in OS 10.7.3 but can't test deployment target to that granularity, so round up. */
+#elif defined (kIOUSBInterfaceInterfaceID500) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
#define usb_interface_t IOUSBInterfaceInterface500
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID500
#define InterfaceVersion 500
-#elif defined (kIOUSBInterfaceInterfaceID300)
+/* New in OS 10.5.0. */
+#elif defined (kIOUSBInterfaceInterfaceID300) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
#define usb_interface_t IOUSBInterfaceInterface300
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300
#define InterfaceVersion 300
-#elif defined (kIOUSBInterfaceInterfaceID245)
+/* New in OS 10.4.5 (or 10.4.6?) but can't test deployment target to that granularity, so round up. */
+#elif defined (kIOUSBInterfaceInterfaceID245) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
#define usb_interface_t IOUSBInterfaceInterface245
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245
#define InterfaceVersion 245
-#elif defined (kIOUSBInterfaceInterfaceID220)
+/* New in OS 10.4.0. */
+#elif defined (kIOUSBInterfaceInterfaceID220) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1040)
#define usb_interface_t IOUSBInterfaceInterface220
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
@@ -66,43 +87,57 @@
#else
-#error "IOUSBFamily is too old. Please upgrade your OS"
+#error "IOUSBFamily is too old. Please upgrade your SDK and/or deployment target"
#endif
/* IOUSBDeviceInterface */
-#if defined (kIOUSBDeviceInterfaceID500) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+
+/* New in OS 10.9.0. */
+#if defined (kIOUSBDeviceInterfaceID650) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
+
+#define usb_device_t IOUSBDeviceInterface650
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID650
+#define DeviceVersion 650
+
+/* New in OS 10.7.3 but can't test deployment target to that granularity, so round up. */
+#elif defined (kIOUSBDeviceInterfaceID500) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
#define usb_device_t IOUSBDeviceInterface500
#define DeviceInterfaceID kIOUSBDeviceInterfaceID500
#define DeviceVersion 500
-#elif defined (kIOUSBDeviceInterfaceID320)
+/* New in OS 10.5.4 but can't test deployment target to that granularity, so round up. */
+#elif defined (kIOUSBDeviceInterfaceID320) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)
#define usb_device_t IOUSBDeviceInterface320
#define DeviceInterfaceID kIOUSBDeviceInterfaceID320
#define DeviceVersion 320
-#elif defined (kIOUSBDeviceInterfaceID300)
+/* New in OS 10.5.0. */
+#elif defined (kIOUSBDeviceInterfaceID300) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
#define usb_device_t IOUSBDeviceInterface300
#define DeviceInterfaceID kIOUSBDeviceInterfaceID300
#define DeviceVersion 300
-#elif defined (kIOUSBDeviceInterfaceID245)
+/* New in OS 10.4.5 (or 10.4.6?) but can't test deployment target to that granularity, so round up. */
+#elif defined (kIOUSBDeviceInterfaceID245) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
#define usb_device_t IOUSBDeviceInterface245
#define DeviceInterfaceID kIOUSBDeviceInterfaceID245
#define DeviceVersion 245
-#elif defined (kIOUSBDeviceInterfaceID220)
+/* New in OS 10.2.3 but can't test deployment target to that granularity, so round up. */
+#elif defined (kIOUSBDeviceInterfaceID197) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1030)
+
#define usb_device_t IOUSBDeviceInterface197
#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
#define DeviceVersion 197
#else
-#error "IOUSBFamily is too old. Please upgrade your OS"
+#error "IOUSBFamily is too old. Please upgrade your SDK and/or deployment target"
#endif
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_pollfs.cpp b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_pollfs.cpp
index e0c771320..e0c771320 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_pollfs.cpp
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_pollfs.cpp
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb.h
index d51ae9eae..d51ae9eae 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb.h
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_backend.cpp b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_backend.cpp
index d3de8cc08..d3de8cc08 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_backend.cpp
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_backend.cpp
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.cpp b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_raw.cpp
index 77adbd1e6..c701e3442 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.cpp
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_raw.cpp
@@ -38,8 +38,9 @@ haiku_init(struct libusb_context *ctx)
}
static void
-haiku_exit(void)
+haiku_exit(struct libusb_context *ctx)
{
+ UNUSED(ctx);
if (atomic_add(&gInitCount, -1) == 1)
gUsbRoster.Stop();
}
@@ -195,11 +196,12 @@ haiku_clock_gettime(int clkid, struct timespec *tp)
return LIBUSB_ERROR_INVALID_PARAM;
}
-const struct usbi_os_backend haiku_usb_raw_backend = {
+const struct usbi_os_backend usbi_backend = {
/*.name =*/ "Haiku usbfs",
/*.caps =*/ 0,
/*.init =*/ haiku_init,
/*.exit =*/ haiku_exit,
+ /*.set_option =*/ NULL,
/*.get_device_list =*/ NULL,
/*.hotplug_poll =*/ NULL,
/*.open =*/ haiku_open,
@@ -244,6 +246,7 @@ const struct usbi_os_backend haiku_usb_raw_backend = {
/*.get_timerfd_clockid =*/ NULL,
#endif
+ /*.context_priv_size=*/ 0,
/*.device_priv_size =*/ sizeof(USBDevice *),
/*.device_handle_priv_size =*/ sizeof(USBDeviceHandle *),
/*.transfer_priv_size =*/ sizeof(USBTransfer *),
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_raw.h
index 5baf53d7c..5baf53d7c 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/haiku_usb_raw.h
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_netlink.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_netlink.c
index 60cf3ad1b..c1ad1ec51 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_netlink.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_netlink.c
@@ -45,24 +45,33 @@
#define NL_GROUP_KERNEL 1
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
+
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK 0
+#endif
+
static int linux_netlink_socket = -1;
static int netlink_control_pipe[2] = { -1, -1 };
static pthread_t libusb_linux_event_thread;
static void *linux_netlink_event_thread_main(void *arg);
-static int set_fd_cloexec_nb(int fd)
+static int set_fd_cloexec_nb(int fd, int socktype)
{
int flags;
#if defined(FD_CLOEXEC)
- flags = fcntl(fd, F_GETFD);
- if (flags == -1) {
- usbi_err(NULL, "failed to get netlink fd flags (%d)", errno);
- return -1;
- }
+ /* Make sure the netlink socket file descriptor is marked as CLOEXEC */
+ if (!(socktype & SOCK_CLOEXEC)) {
+ flags = fcntl(fd, F_GETFD);
+ if (flags == -1) {
+ usbi_err(NULL, "failed to get netlink fd flags (%d)", errno);
+ return -1;
+ }
- if (!(flags & FD_CLOEXEC)) {
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
usbi_err(NULL, "failed to set netlink fd flags (%d)", errno);
return -1;
@@ -70,13 +79,14 @@ static int set_fd_cloexec_nb(int fd)
}
#endif
- flags = fcntl(fd, F_GETFL);
- if (flags == -1) {
- usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno);
- return -1;
- }
+ /* Make sure the netlink socket is non-blocking */
+ if (!(socktype & SOCK_NONBLOCK)) {
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1) {
+ usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno);
+ return -1;
+ }
- if (!(flags & O_NONBLOCK)) {
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
usbi_err(NULL, "failed to set netlink fd status flags (%d)", errno);
return -1;
@@ -89,21 +99,15 @@ static int set_fd_cloexec_nb(int fd)
int linux_netlink_start_event_monitor(void)
{
struct sockaddr_nl sa_nl = { .nl_family = AF_NETLINK, .nl_groups = NL_GROUP_KERNEL };
- int socktype = SOCK_RAW;
+ int socktype = SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC;
int opt = 1;
int ret;
-#if defined(SOCK_CLOEXEC)
- socktype |= SOCK_CLOEXEC;
-#endif
-#if defined(SOCK_NONBLOCK)
- socktype |= SOCK_NONBLOCK;
-#endif
-
linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
if (linux_netlink_socket == -1 && errno == EINVAL) {
usbi_dbg("failed to create netlink socket of type %d, attempting SOCK_RAW", socktype);
- linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
+ socktype = SOCK_RAW;
+ linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
}
if (linux_netlink_socket == -1) {
@@ -111,7 +115,7 @@ int linux_netlink_start_event_monitor(void)
goto err;
}
- ret = set_fd_cloexec_nb(linux_netlink_socket);
+ ret = set_fd_cloexec_nb(linux_netlink_socket, socktype);
if (ret == -1)
goto err_close_socket;
@@ -162,7 +166,7 @@ int linux_netlink_stop_event_monitor(void)
/* Write some dummy data to the control pipe and
* wait for the thread to exit */
- r = usbi_write(netlink_control_pipe[1], &dummy, sizeof(dummy));
+ r = write(netlink_control_pipe[1], &dummy, sizeof(dummy));
if (r <= 0)
usbi_warn(NULL, "netlink control pipe signal failed");
@@ -356,7 +360,8 @@ static int linux_netlink_read_message(void)
static void *linux_netlink_event_thread_main(void *arg)
{
char dummy;
- ssize_t r;
+ int r;
+ ssize_t nb;
struct pollfd fds[] = {
{ .fd = netlink_control_pipe[0],
.events = POLLIN },
@@ -368,11 +373,15 @@ static void *linux_netlink_event_thread_main(void *arg)
usbi_dbg("netlink event thread entering");
- while (poll(fds, 2, -1) >= 0) {
+ while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) {
+ if (r < 0) {
+ /* temporary failure */
+ continue;
+ }
if (fds[0].revents & POLLIN) {
/* activity on control pipe, read the byte and exit */
- r = usbi_read(netlink_control_pipe[0], &dummy, sizeof(dummy));
- if (r <= 0)
+ nb = read(netlink_control_pipe[0], &dummy, sizeof(dummy));
+ if (nb <= 0)
usbi_warn(NULL, "netlink control pipe read failed");
break;
}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_udev.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_udev.c
index 61d953d8c..c97806ba6 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_udev.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_udev.c
@@ -82,17 +82,33 @@ int linux_udev_start_event_monitor(void)
udev_monitor_fd = udev_monitor_get_fd(udev_monitor);
+#if defined(FD_CLOEXEC)
+ /* Make sure the udev file descriptor is marked as CLOEXEC */
+ r = fcntl(udev_monitor_fd, F_GETFD);
+ if (r == -1) {
+ usbi_err(NULL, "geting udev monitor fd flags (%d)", errno);
+ goto err_free_monitor;
+ }
+ if (!(r & FD_CLOEXEC)) {
+ if (fcntl(udev_monitor_fd, F_SETFD, r | FD_CLOEXEC) == -1) {
+ usbi_err(NULL, "setting udev monitor fd flags (%d)", errno);
+ goto err_free_monitor;
+ }
+ }
+#endif
+
/* Some older versions of udev are not non-blocking by default,
* so make sure this is set */
r = fcntl(udev_monitor_fd, F_GETFL);
if (r == -1) {
- usbi_err(NULL, "getting udev monitor fd flags (%d)", errno);
+ usbi_err(NULL, "getting udev monitor fd status flags (%d)", errno);
goto err_free_monitor;
}
- r = fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK);
- if (r) {
- usbi_err(NULL, "setting udev monitor fd flags (%d)", errno);
- goto err_free_monitor;
+ if (!(r & O_NONBLOCK)) {
+ if (fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK) == -1) {
+ usbi_err(NULL, "setting udev monitor fd status flags (%d)", errno);
+ goto err_free_monitor;
+ }
}
r = usbi_pipe(udev_control_pipe);
@@ -134,7 +150,7 @@ int linux_udev_stop_event_monitor(void)
/* Write some dummy data to the control pipe and
* wait for the thread to exit */
- r = usbi_write(udev_control_pipe[1], &dummy, sizeof(dummy));
+ r = write(udev_control_pipe[1], &dummy, sizeof(dummy));
if (r <= 0) {
usbi_warn(NULL, "udev control pipe signal failed");
}
@@ -162,6 +178,7 @@ static void *linux_udev_event_thread_main(void *arg)
{
char dummy;
int r;
+ ssize_t nb;
struct udev_device* udev_dev;
struct pollfd fds[] = {
{.fd = udev_control_pipe[0],
@@ -179,8 +196,8 @@ static void *linux_udev_event_thread_main(void *arg)
}
if (fds[0].revents & POLLIN) {
/* activity on control pipe, read the byte and exit */
- r = usbi_read(udev_control_pipe[0], &dummy, sizeof(dummy));
- if (r <= 0) {
+ nb = read(udev_control_pipe[0], &dummy, sizeof(dummy));
+ if (nb <= 0) {
usbi_warn(NULL, "udev control pipe read failed");
}
break;
@@ -274,6 +291,7 @@ int linux_udev_scan_devices(struct libusb_context *ctx)
udev_enumerate_scan_devices(enumerator);
devices = udev_enumerate_get_list_entry(enumerator);
+ entry = NULL;
udev_list_entry_foreach(entry, devices) {
const char *path = udev_list_entry_get_name(entry);
uint8_t busnum = 0, devaddr = 0;
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_usbfs.c
index 6b89ba288..768e7d5a6 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_usbfs.c
@@ -81,6 +81,19 @@ static const char *usbfs_path = NULL;
/* use usbdev*.* device names in /dev instead of the usbfs bus directories */
static int usbdev_names = 0;
+/* Linux has changed the maximum length of an individual isochronous packet
+ * over time. Initially this limit was 1,023 bytes, but Linux 2.6.18
+ * (commit 3612242e527eb47ee4756b5350f8bdf791aa5ede) increased this value to
+ * 8,192 bytes to support higher bandwidth devices. Linux 3.10
+ * (commit e2e2f0ea1c935edcf53feb4c4c8fdb4f86d57dd9) further increased this
+ * value to 49,152 bytes to support super speed devices.
+ */
+static unsigned int max_iso_packet_len = 0;
+
+/* Linux 2.6.23 adds support for O_CLOEXEC when opening files, which marks the
+ * close-on-exec flag in the underlying file descriptor. */
+static int supports_flag_cloexec = -1;
+
/* Linux 2.6.32 adds support for a bulk continuation URB flag. this basically
* allows us to mark URBs as being part of a specific logical transfer when
* we submit them to the kernel. then, on any error except a cancellation, all
@@ -136,6 +149,12 @@ static int detach_kernel_driver_and_claim(struct libusb_device_handle *, int);
static int linux_default_scan_devices (struct libusb_context *ctx);
#endif
+struct kernel_version {
+ int major;
+ int minor;
+ int sublevel;
+};
+
struct linux_device_priv {
char *sysfs_dir;
unsigned char *descriptors;
@@ -180,6 +199,16 @@ struct linux_transfer_priv {
int iso_packet_offset;
};
+static int _open(const char *path, int flags)
+{
+#if defined(O_CLOEXEC)
+ if (supports_flag_cloexec)
+ return open(path, flags | O_CLOEXEC);
+ else
+#endif
+ return open(path, flags);
+}
+
static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent)
{
struct libusb_context *ctx = DEVICE_CTX(dev);
@@ -194,7 +223,7 @@ static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent)
snprintf(path, PATH_MAX, "%s/%03d/%03d",
usbfs_path, dev->bus_number, dev->device_address);
- fd = open(path, mode);
+ fd = _open(path, mode);
if (fd != -1)
return fd; /* Success */
@@ -205,7 +234,7 @@ static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent)
/* Wait 10ms for USB device path creation.*/
nanosleep(&(struct timespec){delay / 1000000, (delay * 1000) % 1000000000UL}, NULL);
- fd = open(path, mode);
+ fd = _open(path, mode);
if (fd != -1)
return fd; /* Success */
}
@@ -342,39 +371,59 @@ static clockid_t find_monotonic_clock(void)
return CLOCK_REALTIME;
}
-static int kernel_version_ge(int major, int minor, int sublevel)
+static int get_kernel_version(struct libusb_context *ctx,
+ struct kernel_version *ver)
{
struct utsname uts;
- int atoms, kmajor, kminor, ksublevel;
+ int atoms;
- if (uname(&uts) < 0)
+ if (uname(&uts) < 0) {
+ usbi_err(ctx, "uname failed, errno %d", errno);
return -1;
- atoms = sscanf(uts.release, "%d.%d.%d", &kmajor, &kminor, &ksublevel);
- if (atoms < 1)
+ }
+
+ atoms = sscanf(uts.release, "%d.%d.%d", &ver->major, &ver->minor, &ver->sublevel);
+ if (atoms < 1) {
+ usbi_err(ctx, "failed to parse uname release '%s'", uts.release);
return -1;
+ }
+
+ if (atoms < 2)
+ ver->minor = -1;
+ if (atoms < 3)
+ ver->sublevel = -1;
- if (kmajor > major)
+ usbi_dbg("reported kernel version is %s", uts.release);
+
+ return 0;
+}
+
+static int kernel_version_ge(const struct kernel_version *ver,
+ int major, int minor, int sublevel)
+{
+ if (ver->major > major)
return 1;
- if (kmajor < major)
+ else if (ver->major < major)
return 0;
/* kmajor == major */
- if (atoms < 2)
+ if (ver->minor == -1 && ver->sublevel == -1)
return 0 == minor && 0 == sublevel;
- if (kminor > minor)
+ else if (ver->minor > minor)
return 1;
- if (kminor < minor)
+ else if (ver->minor < minor)
return 0;
/* kminor == minor */
- if (atoms < 3)
+ if (ver->sublevel == -1)
return 0 == sublevel;
- return ksublevel >= sublevel;
+ return ver->sublevel >= sublevel;
}
static int op_init(struct libusb_context *ctx)
{
+ struct kernel_version kversion;
struct stat statbuf;
int r;
@@ -387,13 +436,17 @@ static int op_init(struct libusb_context *ctx)
if (monotonic_clkid == -1)
monotonic_clkid = find_monotonic_clock();
+ if (get_kernel_version(ctx, &kversion) < 0)
+ return LIBUSB_ERROR_OTHER;
+
+ if (supports_flag_cloexec == -1) {
+ /* O_CLOEXEC flag available from Linux 2.6.23 */
+ supports_flag_cloexec = kernel_version_ge(&kversion,2,6,23);
+ }
+
if (supports_flag_bulk_continuation == -1) {
/* bulk continuation URB flag available from Linux 2.6.32 */
- supports_flag_bulk_continuation = kernel_version_ge(2,6,32);
- if (supports_flag_bulk_continuation == -1) {
- usbi_err(ctx, "error checking for bulk continuation support");
- return LIBUSB_ERROR_OTHER;
- }
+ supports_flag_bulk_continuation = kernel_version_ge(&kversion,2,6,32);
}
if (supports_flag_bulk_continuation)
@@ -401,32 +454,31 @@ static int op_init(struct libusb_context *ctx)
if (-1 == supports_flag_zero_packet) {
/* zero length packet URB flag fixed since Linux 2.6.31 */
- supports_flag_zero_packet = kernel_version_ge(2,6,31);
- if (-1 == supports_flag_zero_packet) {
- usbi_err(ctx, "error checking for zero length packet support");
- return LIBUSB_ERROR_OTHER;
- }
+ supports_flag_zero_packet = kernel_version_ge(&kversion,2,6,31);
}
if (supports_flag_zero_packet)
usbi_dbg("zero length packet flag supported");
+ if (!max_iso_packet_len) {
+ if (kernel_version_ge(&kversion,3,10,0))
+ max_iso_packet_len = 49152;
+ else if (kernel_version_ge(&kversion,2,6,18))
+ max_iso_packet_len = 8192;
+ else
+ max_iso_packet_len = 1023;
+ }
+
+ usbi_dbg("max iso packet length is (likely) %u bytes", max_iso_packet_len);
+
if (-1 == sysfs_has_descriptors) {
/* sysfs descriptors has all descriptors since Linux 2.6.26 */
- sysfs_has_descriptors = kernel_version_ge(2,6,26);
- if (-1 == sysfs_has_descriptors) {
- usbi_err(ctx, "error checking for sysfs descriptors");
- return LIBUSB_ERROR_OTHER;
- }
+ sysfs_has_descriptors = kernel_version_ge(&kversion,2,6,26);
}
if (-1 == sysfs_can_relate_devices) {
/* sysfs has busnum since Linux 2.6.22 */
- sysfs_can_relate_devices = kernel_version_ge(2,6,22);
- if (-1 == sysfs_can_relate_devices) {
- usbi_err(ctx, "error checking for sysfs busnum");
- return LIBUSB_ERROR_OTHER;
- }
+ sysfs_can_relate_devices = kernel_version_ge(&kversion,2,6,22);
}
if (sysfs_can_relate_devices || sysfs_has_descriptors) {
@@ -463,8 +515,9 @@ static int op_init(struct libusb_context *ctx)
return r;
}
-static void op_exit(void)
+static void op_exit(struct libusb_context *ctx)
{
+ UNUSED(ctx);
usbi_mutex_static_lock(&linux_hotplug_startstop_lock);
assert(init_count != 0);
if (!--init_count) {
@@ -526,7 +579,7 @@ static int _open_sysfs_attr(struct libusb_device *dev, const char *attr)
snprintf(filename, PATH_MAX, "%s/%s/%s",
SYSFS_DEVICE_PATH, priv->sysfs_dir, attr);
- fd = open(filename, O_RDONLY);
+ fd = _open(filename, O_RDONLY);
if (fd < 0) {
usbi_err(DEVICE_CTX(dev),
"open %s failed ret=%d errno=%d", filename, fd, errno);
@@ -542,12 +595,12 @@ static int __read_sysfs_attr(struct libusb_context *ctx,
{
char filename[PATH_MAX];
FILE *f;
- int r, value;
+ int fd, r, value;
snprintf(filename, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH,
devname, attr);
- f = fopen(filename, "r");
- if (f == NULL) {
+ fd = _open(filename, O_RDONLY);
+ if (fd == -1) {
if (errno == ENOENT) {
/* File doesn't exist. Assume the device has been
disconnected (see trac ticket #70). */
@@ -557,6 +610,13 @@ static int __read_sysfs_attr(struct libusb_context *ctx,
return LIBUSB_ERROR_IO;
}
+ f = fdopen(fd, "r");
+ if (f == NULL) {
+ usbi_err(ctx, "fdopen %s failed errno=%d", filename, errno);
+ close(fd);
+ return LIBUSB_ERROR_OTHER;
+ }
+
r = fscanf(f, "%d", &value);
fclose(f);
if (r != 1) {
@@ -806,7 +866,7 @@ static int op_get_active_config_descriptor(struct libusb_device *dev,
if (r < 0)
return r;
- len = MIN(len, r);
+ len = MIN(len, (size_t)r);
memcpy(buffer, config_desc, len);
return len;
}
@@ -836,7 +896,7 @@ static int op_get_config_descriptor(struct libusb_device *dev,
descriptors += r;
}
- len = MIN(len, r);
+ len = MIN(len, (size_t)r);
memcpy(buffer, descriptors, len);
return len;
}
@@ -911,6 +971,7 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
case 12: dev->speed = LIBUSB_SPEED_FULL; break;
case 480: dev->speed = LIBUSB_SPEED_HIGH; break;
case 5000: dev->speed = LIBUSB_SPEED_SUPER; break;
+ case 10000: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break;
default:
usbi_warn(DEVICE_CTX(dev), "Unknown device speed: %d Mbps", speed);
}
@@ -1239,11 +1300,12 @@ static int sysfs_get_device_list(struct libusb_context *ctx)
{
DIR *devices = opendir(SYSFS_DEVICE_PATH);
struct dirent *entry;
- int r = LIBUSB_ERROR_IO;
+ int num_devices = 0;
+ int num_enumerated = 0;
if (!devices) {
usbi_err(ctx, "opendir devices failed errno=%d", errno);
- return r;
+ return LIBUSB_ERROR_IO;
}
while ((entry = readdir(devices))) {
@@ -1251,16 +1313,23 @@ static int sysfs_get_device_list(struct libusb_context *ctx)
|| strchr(entry->d_name, ':'))
continue;
+ num_devices++;
+
if (sysfs_scan_device(ctx, entry->d_name)) {
usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
continue;
}
- r = 0;
+ num_enumerated++;
}
closedir(devices);
- return r;
+
+ /* successful if at least one device was enumerated or no devices were found */
+ if (num_enumerated || !num_devices)
+ return LIBUSB_SUCCESS;
+ else
+ return LIBUSB_ERROR_IO;
}
static int linux_default_scan_devices (struct libusb_context *ctx)
@@ -1685,10 +1754,7 @@ static int detach_kernel_driver_and_claim(struct libusb_device_handle *handle,
strcpy(dc.driver, "usbfs");
dc.flags = USBFS_DISCONNECT_CLAIM_EXCEPT_DRIVER;
r = ioctl(fd, IOCTL_USBFS_DISCONNECT_CLAIM, &dc);
- if (r == 0 || (r != 0 && errno != ENOTTY)) {
- if (r == 0)
- return 0;
-
+ if (r != 0 && errno != ENOTTY) {
switch (errno) {
case EBUSY:
return LIBUSB_ERROR_BUSY;
@@ -1700,7 +1766,8 @@ static int detach_kernel_driver_and_claim(struct libusb_device_handle *handle,
usbi_err(HANDLE_CTX(handle),
"disconnect-and-claim failed errno %d", errno);
return LIBUSB_ERROR_OTHER;
- }
+ } else if (r == 0)
+ return 0;
/* Fallback code for kernels which don't support the
disconnect-and-claim ioctl */
@@ -1973,38 +2040,43 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
struct linux_device_handle_priv *dpriv =
_device_handle_priv(transfer->dev_handle);
struct usbfs_urb **urbs;
- size_t alloc_size;
int num_packets = transfer->num_iso_packets;
- int i;
- int this_urb_len = 0;
- int num_urbs = 1;
- int packet_offset = 0;
+ int num_packets_remaining;
+ int i, j;
+ int num_urbs;
unsigned int packet_len;
+ unsigned int total_len = 0;
unsigned char *urb_buffer = transfer->buffer;
+ if (num_packets < 1)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
/* usbfs places arbitrary limits on iso URBs. this limit has changed
- * at least three times, and it's difficult to accurately detect which
- * limit this running kernel might impose. so we attempt to submit
- * whatever the user has provided. if the kernel rejects the request
- * due to its size, we return an error indicating such to the user.
+ * at least three times, but we attempt to detect this limit during
+ * init and check it here. if the kernel rejects the request due to
+ * its size, we return an error indicating such to the user.
*/
-
- /* calculate how many URBs we need */
for (i = 0; i < num_packets; i++) {
- unsigned int space_remaining = MAX_ISO_BUFFER_LENGTH - this_urb_len;
packet_len = transfer->iso_packet_desc[i].length;
- if (packet_len > space_remaining) {
- num_urbs++;
- this_urb_len = packet_len;
- /* check that we can actually support this packet length */
- if (this_urb_len > MAX_ISO_BUFFER_LENGTH)
- return LIBUSB_ERROR_INVALID_PARAM;
- } else {
- this_urb_len += packet_len;
+ if (packet_len > max_iso_packet_len) {
+ usbi_warn(TRANSFER_CTX(transfer),
+ "iso packet length of %u bytes exceeds maximum of %u bytes",
+ packet_len, max_iso_packet_len);
+ return LIBUSB_ERROR_INVALID_PARAM;
}
+
+ total_len += packet_len;
}
- usbi_dbg("need %d %dk URBs for transfer", num_urbs, MAX_ISO_BUFFER_LENGTH / 1024);
+
+ if (transfer->length < (int)total_len)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ /* usbfs limits the number of iso packets per URB */
+ num_urbs = (num_packets + (MAX_ISO_PACKETS_PER_URB - 1)) / MAX_ISO_PACKETS_PER_URB;
+
+ usbi_dbg("need %d urbs for new transfer with length %d", num_urbs,
+ transfer->length);
urbs = calloc(num_urbs, sizeof(*urbs));
if (!urbs)
@@ -2017,31 +2089,15 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
tpriv->iso_packet_offset = 0;
/* allocate + initialize each URB with the correct number of packets */
- for (i = 0; i < num_urbs; i++) {
+ num_packets_remaining = num_packets;
+ for (i = 0, j = 0; i < num_urbs; i++) {
+ int num_packets_in_urb = MIN(num_packets_remaining, MAX_ISO_PACKETS_PER_URB);
struct usbfs_urb *urb;
- unsigned int space_remaining_in_urb = MAX_ISO_BUFFER_LENGTH;
- int urb_packet_offset = 0;
- unsigned char *urb_buffer_orig = urb_buffer;
- int j;
+ size_t alloc_size;
int k;
- /* swallow up all the packets we can fit into this URB */
- while (packet_offset < transfer->num_iso_packets) {
- packet_len = transfer->iso_packet_desc[packet_offset].length;
- if (packet_len <= space_remaining_in_urb) {
- /* throw it in */
- urb_packet_offset++;
- packet_offset++;
- space_remaining_in_urb -= packet_len;
- urb_buffer += packet_len;
- } else {
- /* it can't fit, save it for the next URB */
- break;
- }
- }
-
alloc_size = sizeof(*urb)
- + (urb_packet_offset * sizeof(struct usbfs_iso_packet_desc));
+ + (num_packets_in_urb * sizeof(struct usbfs_iso_packet_desc));
urb = calloc(1, alloc_size);
if (!urb) {
free_iso_urbs(tpriv);
@@ -2050,10 +2106,10 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
urbs[i] = urb;
/* populate packet lengths */
- for (j = 0, k = packet_offset - urb_packet_offset;
- k < packet_offset; k++, j++) {
- packet_len = transfer->iso_packet_desc[k].length;
- urb->iso_frame_desc[j].length = packet_len;
+ for (k = 0; k < num_packets_in_urb; j++, k++) {
+ packet_len = transfer->iso_packet_desc[j].length;
+ urb->buffer_length += packet_len;
+ urb->iso_frame_desc[k].length = packet_len;
}
urb->usercontext = itransfer;
@@ -2061,8 +2117,11 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
/* FIXME: interface for non-ASAP data? */
urb->flags = USBFS_URB_ISO_ASAP;
urb->endpoint = transfer->endpoint;
- urb->number_of_packets = urb_packet_offset;
- urb->buffer = urb_buffer_orig;
+ urb->number_of_packets = num_packets_in_urb;
+ urb->buffer = urb_buffer;
+
+ urb_buffer += urb->buffer_length;
+ num_packets_remaining -= num_packets_in_urb;
}
/* submit URBs */
@@ -2075,6 +2134,10 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
usbi_warn(TRANSFER_CTX(transfer),
"submiturb failed, transfer too large");
r = LIBUSB_ERROR_INVALID_PARAM;
+ } else if (errno == EMSGSIZE) {
+ usbi_warn(TRANSFER_CTX(transfer),
+ "submiturb failed, iso packet length too large");
+ r = LIBUSB_ERROR_INVALID_PARAM;
} else {
usbi_err(TRANSFER_CTX(transfer),
"submiturb failed error %d errno=%d", r, errno);
@@ -2213,7 +2276,6 @@ static void op_clear_transfer_priv(struct usbi_transfer *itransfer)
USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
- /* urbs can be freed also in submit_transfer so lock mutex first */
switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL:
case LIBUSB_TRANSFER_TYPE_BULK:
@@ -2685,7 +2747,7 @@ static clockid_t op_get_timerfd_clockid(void)
}
#endif
-const struct usbi_os_backend linux_usbfs_backend = {
+const struct usbi_os_backend usbi_backend = {
.name = "Linux usbfs",
.caps = USBI_CAP_HAS_HID_ACCESS|USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER,
.init = op_init,
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_usbfs.h
index 8bd3ebcb1..24496325f 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/linux_usbfs.h
@@ -81,10 +81,11 @@ struct usbfs_iso_packet_desc {
unsigned int status;
};
-#define MAX_ISO_BUFFER_LENGTH 49152 * 128
#define MAX_BULK_BUFFER_LENGTH 16384
#define MAX_CTRL_BUFFER_LENGTH 4096
+#define MAX_ISO_PACKETS_PER_URB 128
+
struct usbfs_urb {
unsigned char type;
unsigned char endpoint;
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/netbsd_usb.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/netbsd_usb.c
index ad1ede73e..d9c059a77 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/netbsd_usb.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/netbsd_usb.c
@@ -86,11 +86,12 @@ static int _sync_control_transfer(struct usbi_transfer *);
static int _sync_gen_transfer(struct usbi_transfer *);
static int _access_endpoint(struct libusb_transfer *);
-const struct usbi_os_backend netbsd_backend = {
+const struct usbi_os_backend usbi_backend = {
"Synchronous NetBSD backend",
0,
NULL, /* init() */
NULL, /* exit() */
+ NULL, /* set_option() */
netbsd_get_device_list,
NULL, /* hotplug_poll */
netbsd_open,
@@ -131,6 +132,7 @@ const struct usbi_os_backend netbsd_backend = {
netbsd_handle_transfer_completion,
netbsd_clock_gettime,
+ 0, /* context_priv_size */
sizeof(struct device_priv),
sizeof(struct handle_priv),
0, /* transfer_priv_size */
@@ -212,7 +214,6 @@ error:
int
netbsd_open(struct libusb_device_handle *handle)
{
- struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
dpriv->fd = open(dpriv->devnode, O_RDWR);
@@ -230,7 +231,6 @@ netbsd_open(struct libusb_device_handle *handle)
void
netbsd_close(struct libusb_device_handle *handle)
{
- struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
usbi_dbg("close: fd %d", dpriv->fd);
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/openbsd_usb.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/openbsd_usb.c
index c66025711..f174e496c 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/openbsd_usb.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/openbsd_usb.c
@@ -89,11 +89,12 @@ static int _access_endpoint(struct libusb_transfer *);
static int _bus_open(int);
-const struct usbi_os_backend openbsd_backend = {
+const struct usbi_os_backend usbi_backend = {
"Synchronous OpenBSD backend",
0,
NULL, /* init() */
NULL, /* exit() */
+ NULL, /* set_option() */
obsd_get_device_list,
NULL, /* hotplug_poll */
obsd_open,
@@ -134,6 +135,7 @@ const struct usbi_os_backend openbsd_backend = {
obsd_handle_transfer_completion,
obsd_clock_gettime,
+ 0, /* context_priv_size */
sizeof(struct device_priv),
sizeof(struct handle_priv),
0, /* transfer_priv_size */
@@ -246,7 +248,6 @@ obsd_get_device_list(struct libusb_context * ctx,
int
obsd_open(struct libusb_device_handle *handle)
{
- struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
char devnode[16];
@@ -270,7 +271,6 @@ obsd_open(struct libusb_device_handle *handle)
void
obsd_close(struct libusb_device_handle *handle)
{
- struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
if (dpriv->devname) {
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_posix.c
index e2f55a57a..337714aa6 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_posix.c
@@ -29,25 +29,56 @@
int usbi_pipe(int pipefd[2])
{
+#if defined(HAVE_PIPE2)
+ int ret = pipe2(pipefd, O_CLOEXEC);
+#else
int ret = pipe(pipefd);
+#endif
+
if (ret != 0) {
+ usbi_err(NULL, "failed to create pipe (%d)", errno);
return ret;
}
+
+#if !defined(HAVE_PIPE2) && defined(FD_CLOEXEC)
+ ret = fcntl(pipefd[0], F_GETFD);
+ if (ret == -1) {
+ usbi_err(NULL, "failed to get pipe fd flags (%d)", errno);
+ goto err_close_pipe;
+ }
+ ret = fcntl(pipefd[0], F_SETFD, ret | FD_CLOEXEC);
+ if (ret == -1) {
+ usbi_err(NULL, "failed to set pipe fd flags (%d)", errno);
+ goto err_close_pipe;
+ }
+
+ ret = fcntl(pipefd[1], F_GETFD);
+ if (ret == -1) {
+ usbi_err(NULL, "failed to get pipe fd flags (%d)", errno);
+ goto err_close_pipe;
+ }
+ ret = fcntl(pipefd[1], F_SETFD, ret | FD_CLOEXEC);
+ if (ret == -1) {
+ usbi_err(NULL, "failed to set pipe fd flags (%d)", errno);
+ goto err_close_pipe;
+ }
+#endif
+
ret = fcntl(pipefd[1], F_GETFL);
if (ret == -1) {
- usbi_dbg("Failed to get pipe fd flags: %d", errno);
+ usbi_err(NULL, "failed to get pipe fd status flags (%d)", errno);
goto err_close_pipe;
}
ret = fcntl(pipefd[1], F_SETFL, ret | O_NONBLOCK);
- if (ret != 0) {
- usbi_dbg("Failed to set non-blocking on new pipe: %d", errno);
+ if (ret == -1) {
+ usbi_err(NULL, "failed to set pipe fd status flags (%d)", errno);
goto err_close_pipe;
}
return 0;
err_close_pipe:
- usbi_close(pipefd[0]);
- usbi_close(pipefd[1]);
+ close(pipefd[0]);
+ close(pipefd[1]);
return ret;
}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_posix.h
index 5b4b2c905..5b4b2c905 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_posix.h
diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.c
new file mode 100644
index 000000000..4d283333d
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.c
@@ -0,0 +1,364 @@
+/*
+ * poll_windows: poll compatibility wrapper for Windows
+ * Copyright © 2017 Chris Dickens <christopher.a.dickens@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/*
+ * poll() and pipe() Windows compatibility layer for libusb 1.0
+ *
+ * The way this layer works is by using OVERLAPPED with async I/O transfers, as
+ * OVERLAPPED have an associated event which is flagged for I/O completion.
+ *
+ * For USB pollable async I/O, you would typically:
+ * - obtain a Windows HANDLE to a file or device that has been opened in
+ * OVERLAPPED mode
+ * - call usbi_create_fd with this handle to obtain a custom fd.
+ * - leave the core functions call the poll routine and flag POLLIN/POLLOUT
+ *
+ * The pipe pollable synchronous I/O works using the overlapped event associated
+ * with a fake pipe. The read/write functions are only meant to be used in that
+ * context.
+ */
+#include <config.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "libusbi.h"
+#include "windows_common.h"
+
+// public fd data
+const struct winfd INVALID_WINFD = { -1, NULL };
+
+// private data
+struct file_descriptor {
+ enum fd_type { FD_TYPE_PIPE, FD_TYPE_TRANSFER } type;
+ OVERLAPPED overlapped;
+};
+
+static usbi_mutex_static_t fd_table_lock = USBI_MUTEX_INITIALIZER;
+static struct file_descriptor *fd_table[MAX_FDS];
+
+static struct file_descriptor *create_fd(enum fd_type type)
+{
+ struct file_descriptor *fd = calloc(1, sizeof(*fd));
+ if (fd == NULL)
+ return NULL;
+ fd->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (fd->overlapped.hEvent == NULL) {
+ free(fd);
+ return NULL;
+ }
+ fd->type = type;
+ return fd;
+}
+
+static void free_fd(struct file_descriptor *fd)
+{
+ CloseHandle(fd->overlapped.hEvent);
+ free(fd);
+}
+
+/*
+ * Create both an fd and an OVERLAPPED, so that it can be used with our
+ * polling function
+ * The handle MUST support overlapped transfers (usually requires CreateFile
+ * with FILE_FLAG_OVERLAPPED)
+ * Return a pollable file descriptor struct, or INVALID_WINFD on error
+ *
+ * Note that the fd returned by this function is a per-transfer fd, rather
+ * than a per-session fd and cannot be used for anything else but our
+ * custom functions.
+ * if you plan to do R/W on the same handle, you MUST create 2 fds: one for
+ * read and one for write. Using a single R/W fd is unsupported and will
+ * produce unexpected results
+ */
+struct winfd usbi_create_fd(void)
+{
+ struct file_descriptor *fd;
+ struct winfd wfd;
+
+ fd = create_fd(FD_TYPE_TRANSFER);
+ if (fd == NULL)
+ return INVALID_WINFD;
+
+ usbi_mutex_static_lock(&fd_table_lock);
+ for (wfd.fd = 0; wfd.fd < MAX_FDS; wfd.fd++) {
+ if (fd_table[wfd.fd] != NULL)
+ continue;
+ fd_table[wfd.fd] = fd;
+ break;
+ }
+ usbi_mutex_static_unlock(&fd_table_lock);
+
+ if (wfd.fd == MAX_FDS) {
+ free_fd(fd);
+ return INVALID_WINFD;
+ }
+
+ wfd.overlapped = &fd->overlapped;
+
+ return wfd;
+}
+
+static int check_pollfds(struct pollfd *fds, unsigned int nfds,
+ HANDLE *wait_handles, DWORD *nb_wait_handles)
+{
+ struct file_descriptor *fd;
+ unsigned int n;
+ int nready = 0;
+
+ usbi_mutex_static_lock(&fd_table_lock);
+
+ for (n = 0; n < nfds; ++n) {
+ fds[n].revents = 0;
+
+ // Keep it simple - only allow either POLLIN *or* POLLOUT
+ assert((fds[n].events == POLLIN) || (fds[n].events == POLLOUT));
+ if ((fds[n].events != POLLIN) && (fds[n].events != POLLOUT)) {
+ fds[n].revents = POLLNVAL;
+ nready++;
+ continue;
+ }
+
+ if ((fds[n].fd >= 0) && (fds[n].fd < MAX_FDS))
+ fd = fd_table[fds[n].fd];
+ else
+ fd = NULL;
+
+ assert(fd != NULL);
+ if (fd == NULL) {
+ fds[n].revents = POLLNVAL;
+ nready++;
+ continue;
+ }
+
+ if (HasOverlappedIoCompleted(&fd->overlapped)
+ && (WaitForSingleObject(fd->overlapped.hEvent, 0) == WAIT_OBJECT_0)) {
+ fds[n].revents = fds[n].events;
+ nready++;
+ } else if (wait_handles != NULL) {
+ if (*nb_wait_handles == MAXIMUM_WAIT_OBJECTS) {
+ usbi_warn(NULL, "too many HANDLEs to wait on");
+ continue;
+ }
+ wait_handles[*nb_wait_handles] = fd->overlapped.hEvent;
+ (*nb_wait_handles)++;
+ }
+ }
+
+ usbi_mutex_static_unlock(&fd_table_lock);
+
+ return nready;
+}
+/*
+ * POSIX poll equivalent, using Windows OVERLAPPED
+ * Currently, this function only accepts one of POLLIN or POLLOUT per fd
+ * (but you can create multiple fds from the same handle for read and write)
+ */
+int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout)
+{
+ HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
+ DWORD nb_wait_handles = 0;
+ DWORD ret;
+ int nready;
+
+ nready = check_pollfds(fds, nfds, wait_handles, &nb_wait_handles);
+
+ // If nothing was triggered, wait on all fds that require it
+ if ((nready == 0) && (nb_wait_handles != 0) && (timeout != 0)) {
+ ret = WaitForMultipleObjects(nb_wait_handles, wait_handles,
+ FALSE, (timeout < 0) ? INFINITE : (DWORD)timeout);
+ if (ret < (WAIT_OBJECT_0 + nb_wait_handles)) {
+ nready = check_pollfds(fds, nfds, NULL, NULL);
+ } else if (ret != WAIT_TIMEOUT) {
+ if (ret == WAIT_FAILED)
+ usbi_err(NULL, "WaitForMultipleObjects failed: %u", (unsigned int)GetLastError());
+ nready = -1;
+ }
+ }
+
+ return nready;
+}
+
+/*
+ * close a fake file descriptor
+ */
+int usbi_close(int _fd)
+{
+ struct file_descriptor *fd;
+
+ if (_fd < 0 || _fd >= MAX_FDS)
+ goto err_badfd;
+
+ usbi_mutex_static_lock(&fd_table_lock);
+ fd = fd_table[_fd];
+ fd_table[_fd] = NULL;
+ usbi_mutex_static_unlock(&fd_table_lock);
+
+ if (fd == NULL)
+ goto err_badfd;
+
+ if (fd->type == FD_TYPE_PIPE) {
+ // InternalHigh is our reference count
+ fd->overlapped.InternalHigh--;
+ if (fd->overlapped.InternalHigh == 0)
+ free_fd(fd);
+ } else {
+ free_fd(fd);
+ }
+
+ return 0;
+
+err_badfd:
+ errno = EBADF;
+ return -1;
+}
+
+/*
+* Create a fake pipe.
+* As libusb only uses pipes for signaling, all we need from a pipe is an
+* event. To that extent, we create a single wfd and overlapped as a means
+* to access that event.
+*/
+int usbi_pipe(int filedes[2])
+{
+ struct file_descriptor *fd;
+ int r_fd = -1, w_fd = -1;
+ int i;
+
+ fd = create_fd(FD_TYPE_PIPE);
+ if (fd == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ // Use InternalHigh as a reference count
+ fd->overlapped.Internal = STATUS_PENDING;
+ fd->overlapped.InternalHigh = 2;
+
+ usbi_mutex_static_lock(&fd_table_lock);
+ do {
+ for (i = 0; i < MAX_FDS; i++) {
+ if (fd_table[i] != NULL)
+ continue;
+ if (r_fd == -1) {
+ r_fd = i;
+ } else if (w_fd == -1) {
+ w_fd = i;
+ break;
+ }
+ }
+
+ if (i == MAX_FDS)
+ break;
+
+ fd_table[r_fd] = fd;
+ fd_table[w_fd] = fd;
+
+ } while (0);
+ usbi_mutex_static_unlock(&fd_table_lock);
+
+ if (i == MAX_FDS) {
+ free_fd(fd);
+ errno = EMFILE;
+ return -1;
+ }
+
+ filedes[0] = r_fd;
+ filedes[1] = w_fd;
+
+ return 0;
+}
+
+/*
+ * synchronous write for fake "pipe" signaling
+ */
+ssize_t usbi_write(int fd, const void *buf, size_t count)
+{
+ int error = EBADF;
+
+ UNUSED(buf);
+
+ if (fd < 0 || fd >= MAX_FDS)
+ goto err_out;
+
+ if (count != sizeof(unsigned char)) {
+ usbi_err(NULL, "this function should only used for signaling");
+ error = EINVAL;
+ goto err_out;
+ }
+
+ usbi_mutex_static_lock(&fd_table_lock);
+ if ((fd_table[fd] != NULL) && (fd_table[fd]->type == FD_TYPE_PIPE)) {
+ assert(fd_table[fd]->overlapped.Internal == STATUS_PENDING);
+ assert(fd_table[fd]->overlapped.InternalHigh == 2);
+ fd_table[fd]->overlapped.Internal = STATUS_WAIT_0;
+ SetEvent(fd_table[fd]->overlapped.hEvent);
+ error = 0;
+ }
+ usbi_mutex_static_unlock(&fd_table_lock);
+
+ if (error)
+ goto err_out;
+
+ return sizeof(unsigned char);
+
+err_out:
+ errno = error;
+ return -1;
+}
+
+/*
+ * synchronous read for fake "pipe" signaling
+ */
+ssize_t usbi_read(int fd, void *buf, size_t count)
+{
+ int error = EBADF;
+
+ UNUSED(buf);
+
+ if (fd < 0 || fd >= MAX_FDS)
+ goto err_out;
+
+ if (count != sizeof(unsigned char)) {
+ usbi_err(NULL, "this function should only used for signaling");
+ error = EINVAL;
+ goto err_out;
+ }
+
+ usbi_mutex_static_lock(&fd_table_lock);
+ if ((fd_table[fd] != NULL) && (fd_table[fd]->type == FD_TYPE_PIPE)) {
+ assert(fd_table[fd]->overlapped.Internal == STATUS_WAIT_0);
+ assert(fd_table[fd]->overlapped.InternalHigh == 2);
+ fd_table[fd]->overlapped.Internal = STATUS_PENDING;
+ ResetEvent(fd_table[fd]->overlapped.hEvent);
+ error = 0;
+ }
+ usbi_mutex_static_unlock(&fd_table_lock);
+
+ if (error)
+ goto err_out;
+
+ return sizeof(unsigned char);
+
+err_out:
+ errno = error;
+ return -1;
+}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.h
index aa4c985da..bd22c7f62 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/poll_windows.h
@@ -2,6 +2,7 @@
* Windows compat: POSIX compatibility wrapper
* Copyright © 2012-2013 RealVNC Ltd.
* Copyright © 2009-2010 Pete Batard <pete@akeo.ie>
+ * Copyright © 2016-2018 Chris Dickens <christopher.a.dickens@gmail.com>
* With contributions from Michael Plante, Orin Eman et al.
* Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
*
@@ -40,21 +41,6 @@
#define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2)
-/* Windows versions */
-enum windows_version {
- WINDOWS_CE = -2,
- WINDOWS_UNDEFINED = -1,
- WINDOWS_UNSUPPORTED = 0,
- WINDOWS_XP = 0x51,
- WINDOWS_2003 = 0x52, // Also XP x64
- WINDOWS_VISTA = 0x60,
- WINDOWS_7 = 0x61,
- WINDOWS_8 = 0x62,
- WINDOWS_8_1_OR_LATER = 0x63,
- WINDOWS_MAX
-};
-extern int windows_version;
-
#define MAX_FDS 256
#define POLLIN 0x0001 /* There is data to read */
@@ -65,46 +51,26 @@ extern int windows_version;
#define POLLNVAL 0x0020 /* Invalid request: fd not open */
struct pollfd {
- int fd; /* file descriptor */
- short events; /* requested events */
- short revents; /* returned events */
-};
-
-// access modes
-enum rw_type {
- RW_NONE,
- RW_READ,
- RW_WRITE,
+ int fd; /* file descriptor */
+ short events; /* requested events */
+ short revents; /* returned events */
};
-// fd struct that can be used for polling on Windows
-typedef int cancel_transfer(struct usbi_transfer *itransfer);
-
struct winfd {
- int fd; // what's exposed to libusb core
- HANDLE handle; // what we need to attach overlapped to the I/O op, so we can poll it
- OVERLAPPED* overlapped; // what will report our I/O status
- struct usbi_transfer *itransfer; // Associated transfer, or NULL if completed
- cancel_transfer *cancel_fn; // Function pointer to cancel transfer API
- enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH)
+ int fd; // what's exposed to libusb core
+ OVERLAPPED *overlapped; // what will report our I/O status
};
+
extern const struct winfd INVALID_WINFD;
+struct winfd usbi_create_fd(void);
+
int usbi_pipe(int pipefd[2]);
int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout);
ssize_t usbi_write(int fd, const void *buf, size_t count);
ssize_t usbi_read(int fd, void *buf, size_t count);
int usbi_close(int fd);
-void init_polling(void);
-void exit_polling(void);
-struct winfd usbi_create_fd(HANDLE handle, int access_mode,
- struct usbi_transfer *transfer, cancel_transfer *cancel_fn);
-void usbi_free_fd(struct winfd* winfd);
-struct winfd fd_to_winfd(int fd);
-struct winfd handle_to_winfd(HANDLE handle);
-struct winfd overlapped_to_winfd(OVERLAPPED* overlapped);
-
/*
* Timeval operations
*/
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/sunos_usb.c
index cb608976b..7150a3e9d 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/sunos_usb.c
@@ -21,6 +21,7 @@
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/list.h>
#include <sys/stat.h>
#include <strings.h>
#include <errno.h>
@@ -28,21 +29,34 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <wait.h>
#include <unistd.h>
#include <aio.h>
#include <libdevinfo.h>
+#include <sys/nvpair.h>
+#include <sys/devctl.h>
#include <sys/usb/clients/ugen/usb_ugen.h>
+#include <errno.h>
#include <sys/usb/usba.h>
#include <sys/pci.h>
#include "libusbi.h"
#include "sunos_usb.h"
+#define UPDATEDRV_PATH "/usr/sbin/update_drv"
+#define UPDATEDRV "update_drv"
+
+typedef list_t string_list_t;
+typedef struct string_node {
+ char *string;
+ list_node_t link;
+} string_node_t;
+
/*
* Backend functions
*/
static int sunos_init(struct libusb_context *);
-static void sunos_exit(void);
+static void sunos_exit(struct libusb_context *);
static int sunos_get_device_list(struct libusb_context *,
struct discovered_devs **);
static int sunos_open(struct libusb_device_handle *);
@@ -67,6 +81,162 @@ static int sunos_cancel_transfer(struct usbi_transfer *);
static void sunos_clear_transfer_priv(struct usbi_transfer *);
static int sunos_handle_transfer_completion(struct usbi_transfer *);
static int sunos_clock_gettime(int, struct timespec *);
+static int sunos_kernel_driver_active(struct libusb_device_handle *, int interface);
+static int sunos_detach_kernel_driver (struct libusb_device_handle *dev, int interface_number);
+static int sunos_attach_kernel_driver (struct libusb_device_handle *dev, int interface_number);
+static int sunos_usb_open_ep0(sunos_dev_handle_priv_t *hpriv, sunos_dev_priv_t *dpriv);
+static int sunos_usb_ioctl(struct libusb_device *dev, int cmd);
+
+static struct devctl_iocdata iocdata;
+static int sunos_get_link(di_devlink_t devlink, void *arg)
+{
+ walk_link_t *larg = (walk_link_t *)arg;
+ const char *p;
+ const char *q;
+
+ if (larg->path) {
+ char *content = (char *)di_devlink_content(devlink);
+ char *start = strstr(content, "/devices/");
+ start += strlen("/devices");
+ usbi_dbg("%s", start);
+
+ /* line content must have minor node */
+ if (start == NULL ||
+ strncmp(start, larg->path, larg->len) != 0 ||
+ start[larg->len] != ':')
+ return (DI_WALK_CONTINUE);
+ }
+
+ p = di_devlink_path(devlink);
+ q = strrchr(p, '/');
+ usbi_dbg("%s", q);
+
+ *(larg->linkpp) = strndup(p, strlen(p) - strlen(q));
+
+ return (DI_WALK_TERMINATE);
+}
+
+
+static int sunos_physpath_to_devlink(
+ const char *node_path, const char *match, char **link_path)
+{
+ walk_link_t larg;
+ di_devlink_handle_t hdl;
+
+ *link_path = NULL;
+ larg.linkpp = link_path;
+ if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
+ usbi_dbg("di_devlink_init failure");
+ return (-1);
+ }
+
+ larg.len = strlen(node_path);
+ larg.path = (char *)node_path;
+
+ (void) di_devlink_walk(hdl, match, NULL, DI_PRIMARY_LINK,
+ (void *)&larg, sunos_get_link);
+
+ (void) di_devlink_fini(&hdl);
+
+ if (*link_path == NULL) {
+ usbi_dbg("there is no devlink for this path");
+ return (-1);
+ }
+
+ return 0;
+}
+
+static int
+sunos_usb_ioctl(struct libusb_device *dev, int cmd)
+{
+ int fd;
+ nvlist_t *nvlist;
+ char *end;
+ char *phypath;
+ char *hubpath;
+ char path_arg[PATH_MAX];
+ sunos_dev_priv_t *dpriv;
+ devctl_ap_state_t devctl_ap_state;
+
+ dpriv = (sunos_dev_priv_t *)dev->os_priv;
+ phypath = dpriv->phypath;
+
+ end = strrchr(phypath, '/');
+ if (end == NULL)
+ return (-1);
+ hubpath = strndup(phypath, end - phypath);
+ if (hubpath == NULL)
+ return (-1);
+
+ end = strrchr(hubpath, '@');
+ if (end == NULL) {
+ free(hubpath);
+ return (-1);
+ }
+ end++;
+ usbi_dbg("unitaddr: %s", end);
+
+ nvlist_alloc(&nvlist, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
+ nvlist_add_int32(nvlist, "port", dev->port_number);
+ //find the hub path
+ snprintf(path_arg, sizeof(path_arg), "/devices%s:hubd", hubpath);
+ usbi_dbg("ioctl hub path: %s", path_arg);
+
+ fd = open(path_arg, O_RDONLY);
+ if (fd < 0) {
+ usbi_err(DEVICE_CTX(dev), "open failed: %d (%s)", errno, strerror(errno));
+ nvlist_free(nvlist);
+ free(hubpath);
+ return (-1);
+ }
+
+ memset(&iocdata, 0, sizeof(iocdata));
+ memset(&devctl_ap_state, 0, sizeof(devctl_ap_state));
+
+ nvlist_pack(nvlist, (char **)&iocdata.nvl_user, &iocdata.nvl_usersz, NV_ENCODE_NATIVE, 0);
+
+ iocdata.cmd = DEVCTL_AP_GETSTATE;
+ iocdata.flags = 0;
+ iocdata.c_nodename = "hub";
+ iocdata.c_unitaddr = end;
+ iocdata.cpyout_buf = &devctl_ap_state;
+ usbi_dbg("%p, %d", iocdata.nvl_user, iocdata.nvl_usersz);
+
+ errno = 0;
+ if (ioctl(fd, DEVCTL_AP_GETSTATE, &iocdata) == -1) {
+ usbi_err(DEVICE_CTX(dev), "ioctl failed: fd %d, cmd %x, errno %d (%s)",
+ fd, DEVCTL_AP_GETSTATE, errno, strerror(errno));
+ } else {
+ usbi_dbg("dev rstate: %d", devctl_ap_state.ap_rstate);
+ usbi_dbg("dev ostate: %d", devctl_ap_state.ap_ostate);
+ }
+
+ errno = 0;
+ iocdata.cmd = cmd;
+ if (ioctl(fd, (int)cmd, &iocdata) != 0) {
+ usbi_err(DEVICE_CTX(dev), "ioctl failed: fd %d, cmd %x, errno %d (%s)",
+ fd, cmd, errno, strerror(errno));
+ sleep(2);
+ }
+
+ close(fd);
+ free(iocdata.nvl_user);
+ nvlist_free(nvlist);
+ free(hubpath);
+
+ return (-errno);
+}
+
+static int
+sunos_kernel_driver_active(struct libusb_device_handle *dev, int interface)
+{
+ sunos_dev_priv_t *dpriv;
+ dpriv = (sunos_dev_priv_t *)dev->dev->os_priv;
+
+ usbi_dbg("%s", dpriv->ugenpath);
+
+ return (dpriv->ugenpath == NULL);
+}
/*
* Private functions
@@ -79,11 +249,229 @@ static int sunos_init(struct libusb_context *ctx)
return (LIBUSB_SUCCESS);
}
-static void sunos_exit(void)
+static void sunos_exit(struct libusb_context *ctx)
{
usbi_dbg("");
}
+static string_list_t *
+sunos_new_string_list(void)
+{
+ string_list_t *list;
+
+ list = calloc(1, sizeof(*list));
+ if (list != NULL)
+ list_create(list, sizeof(string_node_t),
+ offsetof(string_node_t, link));
+
+ return (list);
+}
+
+static int
+sunos_append_to_string_list(string_list_t *list, const char *arg)
+{
+ string_node_t *np;
+
+ np = calloc(1, sizeof(*np));
+ if (!np)
+ return (-1);
+
+ np->string = strdup(arg);
+ if (!np->string) {
+ free(np);
+ return (-1);
+ }
+
+ list_insert_tail(list, np);
+
+ return (0);
+}
+
+static void
+sunos_free_string_list(string_list_t *list)
+{
+ string_node_t *np;
+
+ while ((np = list_remove_head(list)) != NULL) {
+ free(np->string);
+ free(np);
+ }
+
+ free(list);
+}
+
+static char **
+sunos_build_argv_list(string_list_t *list)
+{
+ char **argv_list;
+ string_node_t *np;
+ int n;
+
+ n = 1; /* Start at 1 for NULL terminator */
+ for (np = list_head(list); np != NULL; np = list_next(list, np))
+ n++;
+
+ argv_list = calloc(n, sizeof(char *));
+ if (argv_list == NULL)
+ return NULL;
+
+ n = 0;
+ for (np = list_head(list); np != NULL; np = list_next(list, np))
+ argv_list[n++] = np->string;
+
+ return (argv_list);
+}
+
+
+static int
+sunos_exec_command(struct libusb_context *ctx, const char *path,
+ string_list_t *list)
+{
+ pid_t pid;
+ int status;
+ int waitstat;
+ int exit_status;
+ char **argv_list;
+
+ argv_list = sunos_build_argv_list(list);
+ if (argv_list == NULL)
+ return (-1);
+
+ pid = fork();
+ if (pid == 0) {
+ /* child */
+ execv(path, argv_list);
+ _exit(127);
+ } else if (pid > 0) {
+ /* parent */
+ do {
+ waitstat = waitpid(pid, &status, 0);
+ } while ((waitstat == -1 && errno == EINTR) ||
+ (waitstat == 0 && !WIFEXITED(status) && !WIFSIGNALED(status)));
+
+ if (waitstat == 0) {
+ if (WIFEXITED(status))
+ exit_status = WEXITSTATUS(status);
+ else
+ exit_status = WTERMSIG(status);
+ } else {
+ usbi_err(ctx, "waitpid failed: errno %d (%s)", errno, strerror(errno));
+ exit_status = -1;
+ }
+ } else {
+ /* fork failed */
+ usbi_err(ctx, "fork failed: errno %d (%s)", errno, strerror(errno));
+ exit_status = -1;
+ }
+
+ free(argv_list);
+
+ return (exit_status);
+}
+
+static int
+sunos_detach_kernel_driver(struct libusb_device_handle *dev_handle,
+ int interface_number)
+{
+ struct libusb_context *ctx = HANDLE_CTX(dev_handle);
+ string_list_t *list;
+ char path_arg[PATH_MAX];
+ sunos_dev_priv_t *dpriv;
+ int r;
+
+ dpriv = (sunos_dev_priv_t *)dev_handle->dev->os_priv;
+ snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath);
+ usbi_dbg("%s", path_arg);
+
+ list = sunos_new_string_list();
+ if (list == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ /* attach ugen driver */
+ r = 0;
+ r |= sunos_append_to_string_list(list, UPDATEDRV);
+ r |= sunos_append_to_string_list(list, "-a"); /* add rule */
+ r |= sunos_append_to_string_list(list, "-i"); /* specific device */
+ r |= sunos_append_to_string_list(list, path_arg); /* physical path */
+ r |= sunos_append_to_string_list(list, "ugen");
+ if (r) {
+ sunos_free_string_list(list);
+ return (LIBUSB_ERROR_NO_MEM);
+ }
+
+ r = sunos_exec_command(ctx, UPDATEDRV_PATH, list);
+ sunos_free_string_list(list);
+ if (r < 0)
+ return (LIBUSB_ERROR_OTHER);
+
+ /* reconfigure the driver node */
+ r = 0;
+ r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT);
+ r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
+ if (r)
+ usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed");
+
+ snprintf(path_arg, sizeof(path_arg), "^usb/%x.%x", dpriv->dev_descr.idVendor,
+ dpriv->dev_descr.idProduct);
+ sunos_physpath_to_devlink(dpriv->phypath, path_arg, &dpriv->ugenpath);
+
+ if (access(dpriv->ugenpath, F_OK) == -1) {
+ usbi_err(HANDLE_CTX(dev_handle), "fail to detach kernel driver");
+ return (LIBUSB_ERROR_IO);
+ }
+
+ return sunos_usb_open_ep0((sunos_dev_handle_priv_t *)dev_handle->os_priv, dpriv);
+}
+
+static int
+sunos_attach_kernel_driver(struct libusb_device_handle *dev_handle,
+ int interface_number)
+{
+ struct libusb_context *ctx = HANDLE_CTX(dev_handle);
+ string_list_t *list;
+ char path_arg[PATH_MAX];
+ sunos_dev_priv_t *dpriv;
+ int r;
+
+ /* we open the dev in detach driver, so we need close it first. */
+ sunos_close(dev_handle);
+
+ dpriv = (sunos_dev_priv_t *)dev_handle->dev->os_priv;
+ snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath);
+ usbi_dbg("%s", path_arg);
+
+ list = sunos_new_string_list();
+ if (list == NULL)
+ return (LIBUSB_ERROR_NO_MEM);
+
+ /* detach ugen driver */
+ r = 0;
+ r |= sunos_append_to_string_list(list, UPDATEDRV);
+ r |= sunos_append_to_string_list(list, "-d"); /* add rule */
+ r |= sunos_append_to_string_list(list, "-i"); /* specific device */
+ r |= sunos_append_to_string_list(list, path_arg); /* physical path */
+ r |= sunos_append_to_string_list(list, "ugen");
+ if (r) {
+ sunos_free_string_list(list);
+ return (LIBUSB_ERROR_NO_MEM);
+ }
+
+ r = sunos_exec_command(ctx, UPDATEDRV_PATH, list);
+ sunos_free_string_list(list);
+ if (r < 0)
+ return (LIBUSB_ERROR_OTHER);
+
+ /* reconfigure the driver node */
+ r = 0;
+ r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
+ r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT);
+ r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
+ if (r)
+ usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed");
+
+ return 0;
+}
+
static int
sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
{
@@ -93,6 +481,7 @@ sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
uint8_t *rdata;
struct libusb_device_descriptor *descr;
sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
+ char match_str[PATH_MAX];
/* Device descriptors */
proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
@@ -137,7 +526,11 @@ sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
phypath = di_devfs_path(node);
if (phypath) {
dpriv->phypath = strdup(phypath);
+ snprintf(match_str, sizeof(match_str), "^usb/%x.%x", dpriv->dev_descr.idVendor, dpriv->dev_descr.idProduct);
+ usbi_dbg("match is %s", match_str);
+ sunos_physpath_to_devlink(dpriv->phypath, match_str, &dpriv->ugenpath);
di_devfs_path_free(phypath);
+
} else {
free(dpriv->raw_cfgdescr);
@@ -170,111 +563,98 @@ sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
return (LIBUSB_SUCCESS);
}
-
static int
sunos_add_devices(di_devlink_t link, void *arg)
{
struct devlink_cbarg *largs = (struct devlink_cbarg *)arg;
struct node_args *nargs;
- di_node_t myself, pnode;
+ di_node_t myself, dn;
uint64_t session_id = 0;
- uint16_t bdf = 0;
+ uint64_t sid = 0;
+ uint64_t bdf = 0;
struct libusb_device *dev;
sunos_dev_priv_t *devpriv;
- const char *path, *newpath;
- int n, i;
+ int n;
+ int i = 0;
int *addr_prop;
uint8_t bus_number = 0;
+ uint32_t * regbuf = NULL;
+ uint32_t reg;
nargs = (struct node_args *)largs->nargs;
myself = largs->myself;
- if (nargs->last_ugenpath) {
- /* the same node's links */
- return (DI_WALK_CONTINUE);
- }
/*
* Construct session ID.
- * session ID = ...parent hub addr|hub addr|dev addr.
+ * session ID = dev_addr | hub addr |parent hub addr|...|root hub bdf
+ * 8 bits 8bits 8 bits 16bits
*/
- pnode = myself;
- i = 0;
- while (pnode != DI_NODE_NIL) {
- if (di_prop_exists(DDI_DEV_T_ANY, pnode, "root-hub") == 1) {
- /* walk to root */
- uint32_t *regbuf = NULL;
- uint32_t reg;
-
- n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, "reg",
- (int **)&regbuf);
- reg = regbuf[0];
- bdf = (PCI_REG_BUS_G(reg) << 8) |
- (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
- session_id |= (bdf << i * 8);
-
- /* same as 'unit-address' property */
- bus_number =
- (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
-
- usbi_dbg("device bus address=%s:%x",
- di_bus_addr(pnode), bus_number);
+ if (myself == DI_NODE_NIL)
+ return (DI_WALK_CONTINUE);
- break;
- }
+ dn = myself;
+ /* find the root hub */
+ while (di_prop_exists(DDI_DEV_T_ANY, dn, "root-hub") != 1) {
+ usbi_dbg("find_root_hub:%s", di_devfs_path(dn));
+ n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn,
+ "assigned-address", &addr_prop);
+ session_id |= ((addr_prop[0] & 0xff) << i++ * 8);
+ dn = di_parent_node(dn);
+ }
+ /* dn is the root hub node */
+ n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "reg", (int **)&regbuf);
+ reg = regbuf[0];
+ bdf = (PCI_REG_BUS_G(reg) << 8) | (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
+ /* bdf must larger than i*8 bits */
+ session_id |= (bdf << i * 8);
+ bus_number = (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
+
+ usbi_dbg("device bus address=%s:%x, name:%s",
+ di_bus_addr(myself), bus_number, di_node_name(dn));
+ usbi_dbg("session id org:%lx", session_id);
+
+ /* dn is the usb device */
+ for (dn = di_child_node(myself); dn != DI_NODE_NIL; dn = di_sibling_node(dn)) {
+ usbi_dbg("device path:%s", di_devfs_path(dn));
+ /* skip hub devices, because its driver can not been unload */
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "usb-port-count", &addr_prop) != -1)
+ continue;
/* usb_addr */
- n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode,
+ n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn,
"assigned-address", &addr_prop);
if ((n != 1) || (addr_prop[0] == 0)) {
usbi_dbg("cannot get valid usb_addr");
-
- return (DI_WALK_CONTINUE);
+ continue;
}
- session_id |= ((addr_prop[0] & 0xff) << i * 8);
- if (++i > 7)
- break;
+ sid = (session_id << 8) | (addr_prop[0] & 0xff) ;
+ usbi_dbg("session id %lx", sid);
- pnode = di_parent_node(pnode);
- }
-
- path = di_devlink_path(link);
- dev = usbi_get_device_by_session_id(nargs->ctx, session_id);
- if (dev == NULL) {
- dev = usbi_alloc_device(nargs->ctx, session_id);
+ dev = usbi_get_device_by_session_id(nargs->ctx, sid);
if (dev == NULL) {
- usbi_dbg("can't alloc device");
-
- return (DI_WALK_TERMINATE);
- }
- devpriv = (sunos_dev_priv_t *)dev->os_priv;
- if ((newpath = strrchr(path, '/')) == NULL) {
- libusb_unref_device(dev);
-
- return (DI_WALK_TERMINATE);
- }
- devpriv->ugenpath = strndup(path, strlen(path) -
- strlen(newpath));
- dev->bus_number = bus_number;
-
- if (sunos_fill_in_dev_info(myself, dev) != LIBUSB_SUCCESS) {
- libusb_unref_device(dev);
+ dev = usbi_alloc_device(nargs->ctx, sid);
+ if (dev == NULL) {
+ usbi_dbg("can't alloc device");
+ continue;
+ }
+ devpriv = (sunos_dev_priv_t *)dev->os_priv;
+ dev->bus_number = bus_number;
- return (DI_WALK_TERMINATE);
- }
- if (usbi_sanitize_device(dev) < 0) {
- libusb_unref_device(dev);
- usbi_dbg("sanatize failed: ");
- return (DI_WALK_TERMINATE);
+ if (sunos_fill_in_dev_info(dn, dev) != LIBUSB_SUCCESS) {
+ libusb_unref_device(dev);
+ usbi_dbg("get infomation fail");
+ continue;
+ }
+ if (usbi_sanitize_device(dev) < 0) {
+ libusb_unref_device(dev);
+ usbi_dbg("sanatize failed: ");
+ return (DI_WALK_TERMINATE);
+ }
+ } else {
+ devpriv = (sunos_dev_priv_t *)dev->os_priv;
+ usbi_dbg("Dev %s exists", devpriv->ugenpath);
}
- } else {
- usbi_dbg("Dev %s exists", path);
- }
-
- devpriv = (sunos_dev_priv_t *)dev->os_priv;
- if (nargs->last_ugenpath == NULL) {
- /* first device */
- nargs->last_ugenpath = devpriv->ugenpath;
if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) {
usbi_dbg("cannot append device");
@@ -285,11 +665,11 @@ sunos_add_devices(di_devlink_t link, void *arg)
* hereafter. Front end or app should take care of their ref.
*/
libusb_unref_device(dev);
- }
- usbi_dbg("Device %s %s id=0x%llx, devcount:%d, bdf=%x",
- devpriv->ugenpath, path, (uint64_t)session_id,
- (*nargs->discdevs)->len, bdf);
+ usbi_dbg("Device %s %s id=0x%llx, devcount:%d, bdf=%x",
+ devpriv->ugenpath, di_devfs_path(dn), (uint64_t)sid,
+ (*nargs->discdevs)->len, bdf);
+ }
return (DI_WALK_CONTINUE);
}
@@ -303,14 +683,14 @@ sunos_walk_minor_node_link(di_node_t node, void *args)
struct node_args *nargs = (struct node_args *)args;
di_devlink_handle_t devlink_hdl = nargs->dlink_hdl;
- /* walk each minor to find ugen devices */
+ /* walk each minor to find usb devices */
while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
minor_path = di_devfs_minor_path(minor);
arg.nargs = args;
arg.myself = node;
arg.minor = minor;
(void) di_devlink_walk(devlink_hdl,
- "^usb/[0-9a-f]+[.][0-9a-f]+", minor_path,
+ "^usb/hub[0-9]+", minor_path,
DI_PRIMARY_LINK, (void *)&arg, sunos_add_devices);
di_devfs_path_free(minor_path);
}
@@ -496,7 +876,7 @@ sunos_check_device_and_status_open(struct libusb_device_handle *hdl,
usbi_dbg("can't find interface for endpoint 0x%02x",
ep_addr);
- return (LIBUSB_ERROR_ACCESS);
+ return (EACCES);
}
/* create filename */
@@ -603,6 +983,11 @@ sunos_open(struct libusb_device_handle *handle)
hpriv->eps[i].statfd = -1;
}
+ if (sunos_kernel_driver_active(handle, 0)) {
+ /* pretend we can open the device */
+ return (LIBUSB_SUCCESS);
+ }
+
if ((ret = sunos_usb_open_ep0(hpriv, dpriv)) != LIBUSB_SUCCESS) {
usbi_dbg("fail: %d", ret);
return (ret);
@@ -1010,9 +1395,7 @@ void
sunos_destroy_device(struct libusb_device *dev)
{
sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
-
- usbi_dbg("");
-
+ usbi_dbg("destroy everyting");
free(dpriv->raw_cfgdescr);
free(dpriv->ugenpath);
free(dpriv->phypath);
@@ -1254,7 +1637,7 @@ sunos_usb_get_status(int fd)
return (status);
}
-const struct usbi_os_backend sunos_backend = {
+const struct usbi_os_backend usbi_backend = {
.name = "Solaris",
.caps = 0,
.init = sunos_init,
@@ -1276,9 +1659,9 @@ const struct usbi_os_backend sunos_backend = {
.reset_device = sunos_reset_device, /* TODO */
.alloc_streams = NULL,
.free_streams = NULL,
- .kernel_driver_active = NULL,
- .detach_kernel_driver = NULL,
- .attach_kernel_driver = NULL,
+ .kernel_driver_active = sunos_kernel_driver_active,
+ .detach_kernel_driver = sunos_detach_kernel_driver,
+ .attach_kernel_driver = sunos_attach_kernel_driver,
.destroy_device = sunos_destroy_device,
.submit_transfer = sunos_submit_transfer,
.cancel_transfer = sunos_cancel_transfer,
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/sunos_usb.h
index 574166031..52bb3d33a 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/sunos_usb.h
@@ -65,6 +65,12 @@ struct devlink_cbarg {
di_minor_t minor;
};
+typedef struct walk_link {
+ char *path;
+ int len;
+ char **linkpp;
+} walk_link_t;
+
/* AIO callback args */
struct aio_callback_args{
struct libusb_transfer *transfer;
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.c
index a4f270bbe..16a7578b8 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.c
@@ -29,7 +29,7 @@
# include <unistd.h>
# include <sys/syscall.h>
#elif defined(__APPLE__)
-# include <mach/mach.h>
+# include <pthread.h>
#elif defined(__CYGWIN__)
# include <windows.h>
#endif
@@ -43,7 +43,7 @@ int usbi_cond_timedwait(pthread_cond_t *cond,
struct timespec timeout;
int r;
- r = usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &timeout);
+ r = usbi_backend.clock_gettime(USBI_CLOCK_REALTIME, &timeout);
if (r < 0)
return r;
@@ -59,7 +59,7 @@ int usbi_cond_timedwait(pthread_cond_t *cond,
int usbi_get_tid(void)
{
- int ret = -1;
+ int ret;
#if defined(__ANDROID__)
ret = gettid();
#elif defined(__linux__)
@@ -69,10 +69,11 @@ int usbi_get_tid(void)
real thread support. For 5.1 and earlier, -1 is returned. */
ret = syscall(SYS_getthrid);
#elif defined(__APPLE__)
- ret = mach_thread_self();
- mach_port_deallocate(mach_task_self(), ret);
+ ret = (int)pthread_mach_thread_np(pthread_self());
#elif defined(__CYGWIN__)
ret = GetCurrentThreadId();
+#else
+ ret = -1;
#endif
/* TODO: NetBSD thread ID support */
return ret;
diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.h
new file mode 100644
index 000000000..9f1ef94bc
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_posix.h
@@ -0,0 +1,102 @@
+/*
+ * libusb synchronization using POSIX Threads
+ *
+ * Copyright © 2010 Peter Stuge <peter@stuge.se>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBUSB_THREADS_POSIX_H
+#define LIBUSB_THREADS_POSIX_H
+
+#include <pthread.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+typedef pthread_mutex_t usbi_mutex_static_t;
+static inline void usbi_mutex_static_lock(usbi_mutex_static_t *mutex)
+{
+ (void)pthread_mutex_lock(mutex);
+}
+static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex)
+{
+ (void)pthread_mutex_unlock(mutex);
+}
+
+typedef pthread_mutex_t usbi_mutex_t;
+static inline int usbi_mutex_init(usbi_mutex_t *mutex)
+{
+ return pthread_mutex_init(mutex, NULL);
+}
+static inline void usbi_mutex_lock(usbi_mutex_t *mutex)
+{
+ (void)pthread_mutex_lock(mutex);
+}
+static inline void usbi_mutex_unlock(usbi_mutex_t *mutex)
+{
+ (void)pthread_mutex_unlock(mutex);
+}
+static inline int usbi_mutex_trylock(usbi_mutex_t *mutex)
+{
+ return pthread_mutex_trylock(mutex);
+}
+static inline void usbi_mutex_destroy(usbi_mutex_t *mutex)
+{
+ (void)pthread_mutex_destroy(mutex);
+}
+
+typedef pthread_cond_t usbi_cond_t;
+static inline void usbi_cond_init(pthread_cond_t *cond)
+{
+ (void)pthread_cond_init(cond, NULL);
+}
+static inline int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
+{
+ return pthread_cond_wait(cond, mutex);
+}
+int usbi_cond_timedwait(usbi_cond_t *cond,
+ usbi_mutex_t *mutex, const struct timeval *tv);
+static inline void usbi_cond_broadcast(usbi_cond_t *cond)
+{
+ (void)pthread_cond_broadcast(cond);
+}
+static inline void usbi_cond_destroy(usbi_cond_t *cond)
+{
+ (void)pthread_cond_destroy(cond);
+}
+
+typedef pthread_key_t usbi_tls_key_t;
+static inline void usbi_tls_key_create(usbi_tls_key_t *key)
+{
+ (void)pthread_key_create(key, NULL);
+}
+static inline void *usbi_tls_key_get(usbi_tls_key_t key)
+{
+ return pthread_getspecific(key);
+}
+static inline void usbi_tls_key_set(usbi_tls_key_t key, void *ptr)
+{
+ (void)pthread_setspecific(key, ptr);
+}
+static inline void usbi_tls_key_delete(usbi_tls_key_t key)
+{
+ (void)pthread_key_delete(key);
+}
+
+int usbi_get_tid(void);
+
+#endif /* LIBUSB_THREADS_POSIX_H */
diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.c
new file mode 100644
index 000000000..409c49055
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.c
@@ -0,0 +1,126 @@
+/*
+ * libusb synchronization on Microsoft Windows
+ *
+ * Copyright © 2010 Michael Plante <michael.plante@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <errno.h>
+
+#include "libusbi.h"
+
+struct usbi_cond_perthread {
+ struct list_head list;
+ HANDLE event;
+};
+
+void usbi_mutex_static_lock(usbi_mutex_static_t *mutex)
+{
+ while (InterlockedExchange(mutex, 1L) == 1L)
+ SleepEx(0, TRUE);
+}
+
+void usbi_cond_init(usbi_cond_t *cond)
+{
+ list_init(&cond->waiters);
+ list_init(&cond->not_waiting);
+}
+
+static int usbi_cond_intwait(usbi_cond_t *cond,
+ usbi_mutex_t *mutex, DWORD timeout_ms)
+{
+ struct usbi_cond_perthread *pos;
+ DWORD r;
+
+ // Same assumption as usbi_cond_broadcast() holds
+ if (list_empty(&cond->not_waiting)) {
+ pos = malloc(sizeof(*pos));
+ if (pos == NULL)
+ return ENOMEM; // This errno is not POSIX-allowed.
+ pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset.
+ if (pos->event == NULL) {
+ free(pos);
+ return ENOMEM;
+ }
+ } else {
+ pos = list_first_entry(&cond->not_waiting, struct usbi_cond_perthread, list);
+ list_del(&pos->list); // remove from not_waiting list.
+ // Ensure the event is clear before waiting
+ WaitForSingleObject(pos->event, 0);
+ }
+
+ list_add(&pos->list, &cond->waiters);
+
+ LeaveCriticalSection(mutex);
+ r = WaitForSingleObject(pos->event, timeout_ms);
+ EnterCriticalSection(mutex);
+
+ list_del(&pos->list);
+ list_add(&pos->list, &cond->not_waiting);
+
+ if (r == WAIT_OBJECT_0)
+ return 0;
+ else if (r == WAIT_TIMEOUT)
+ return ETIMEDOUT;
+ else
+ return EINVAL;
+}
+
+// N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot!
+int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
+{
+ return usbi_cond_intwait(cond, mutex, INFINITE);
+}
+
+int usbi_cond_timedwait(usbi_cond_t *cond,
+ usbi_mutex_t *mutex, const struct timeval *tv)
+{
+ DWORD millis;
+
+ millis = (DWORD)(tv->tv_sec * 1000) + (tv->tv_usec / 1000);
+ /* round up to next millisecond */
+ if (tv->tv_usec % 1000)
+ millis++;
+ return usbi_cond_intwait(cond, mutex, millis);
+}
+
+void usbi_cond_broadcast(usbi_cond_t *cond)
+{
+ // Assumes mutex is locked; this is not in keeping with POSIX spec, but
+ // libusb does this anyway, so we simplify by not adding more sync
+ // primitives to the CV definition!
+ struct usbi_cond_perthread *pos;
+
+ list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread)
+ SetEvent(pos->event);
+ // The wait function will remove its respective item from the list.
+}
+
+void usbi_cond_destroy(usbi_cond_t *cond)
+{
+ // This assumes no one is using this anymore. The check MAY NOT BE safe.
+ struct usbi_cond_perthread *pos, *next;
+
+ if (!list_empty(&cond->waiters))
+ return; // (!see above!)
+ list_for_each_entry_safe(pos, next, &cond->not_waiting, list, struct usbi_cond_perthread) {
+ CloseHandle(pos->event);
+ list_del(&pos->list);
+ free(pos);
+ }
+}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.h
index e97ee7875..409de2d0e 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/threads_windows.h
@@ -21,17 +21,40 @@
#ifndef LIBUSB_THREADS_WINDOWS_H
#define LIBUSB_THREADS_WINDOWS_H
-#define usbi_mutex_static_t volatile LONG
-#define USBI_MUTEX_INITIALIZER 0
-
-#define usbi_mutex_t HANDLE
+#define USBI_MUTEX_INITIALIZER 0L
+#ifdef _WIN32_WCE
+typedef LONG usbi_mutex_static_t;
+#else
+typedef volatile LONG usbi_mutex_static_t;
+#endif
+void usbi_mutex_static_lock(usbi_mutex_static_t *mutex);
+static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex)
+{
+ InterlockedExchange(mutex, 0L);
+}
-typedef struct usbi_cond {
- // Every time a thread touches the CV, it winds up in one of these lists.
- // It stays there until the CV is destroyed, even if the thread terminates.
- struct list_head waiters;
- struct list_head not_waiting;
-} usbi_cond_t;
+typedef CRITICAL_SECTION usbi_mutex_t;
+static inline int usbi_mutex_init(usbi_mutex_t *mutex)
+{
+ InitializeCriticalSection(mutex);
+ return 0;
+}
+static inline void usbi_mutex_lock(usbi_mutex_t *mutex)
+{
+ EnterCriticalSection(mutex);
+}
+static inline void usbi_mutex_unlock(usbi_mutex_t *mutex)
+{
+ LeaveCriticalSection(mutex);
+}
+static inline int usbi_mutex_trylock(usbi_mutex_t *mutex)
+{
+ return !TryEnterCriticalSection(mutex);
+}
+static inline void usbi_mutex_destroy(usbi_mutex_t *mutex)
+{
+ DeleteCriticalSection(mutex);
+}
// We *were* getting timespec from pthread.h:
#if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED))
@@ -45,32 +68,44 @@ struct timespec {
// We *were* getting ETIMEDOUT from pthread.h:
#ifndef ETIMEDOUT
-# define ETIMEDOUT 10060 /* This is the value in winsock.h. */
+#define ETIMEDOUT 10060 /* This is the value in winsock.h. */
#endif
-#define usbi_tls_key_t DWORD
-
-int usbi_mutex_static_lock(usbi_mutex_static_t *mutex);
-int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex);
-
-int usbi_mutex_init(usbi_mutex_t *mutex);
-int usbi_mutex_lock(usbi_mutex_t *mutex);
-int usbi_mutex_unlock(usbi_mutex_t *mutex);
-int usbi_mutex_trylock(usbi_mutex_t *mutex);
-int usbi_mutex_destroy(usbi_mutex_t *mutex);
+typedef struct usbi_cond {
+ // Every time a thread touches the CV, it winds up in one of these lists.
+ // It stays there until the CV is destroyed, even if the thread terminates.
+ struct list_head waiters;
+ struct list_head not_waiting;
+} usbi_cond_t;
-int usbi_cond_init(usbi_cond_t *cond);
+void usbi_cond_init(usbi_cond_t *cond);
int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex);
int usbi_cond_timedwait(usbi_cond_t *cond,
usbi_mutex_t *mutex, const struct timeval *tv);
-int usbi_cond_broadcast(usbi_cond_t *cond);
-int usbi_cond_destroy(usbi_cond_t *cond);
+void usbi_cond_broadcast(usbi_cond_t *cond);
+void usbi_cond_destroy(usbi_cond_t *cond);
-int usbi_tls_key_create(usbi_tls_key_t *key);
-void *usbi_tls_key_get(usbi_tls_key_t key);
-int usbi_tls_key_set(usbi_tls_key_t key, void *value);
-int usbi_tls_key_delete(usbi_tls_key_t key);
+typedef DWORD usbi_tls_key_t;
+static inline void usbi_tls_key_create(usbi_tls_key_t *key)
+{
+ *key = TlsAlloc();
+}
+static inline void *usbi_tls_key_get(usbi_tls_key_t key)
+{
+ return TlsGetValue(key);
+}
+static inline void usbi_tls_key_set(usbi_tls_key_t key, void *ptr)
+{
+ (void)TlsSetValue(key, ptr);
+}
+static inline void usbi_tls_key_delete(usbi_tls_key_t key)
+{
+ (void)TlsFree(key);
+}
-int usbi_get_tid(void);
+static inline int usbi_get_tid(void)
+{
+ return (int)GetCurrentThreadId();
+}
#endif /* LIBUSB_THREADS_WINDOWS_H */
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/wince_usb.c
index 0d466b8c9..a0f35e93e 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/wince_usb.c
@@ -31,7 +31,7 @@
#include "wince_usb.h"
// Global variables
-int windows_version = WINDOWS_CE;
+int errno = 0;
static uint64_t hires_frequency, hires_ticks_to_ps;
static HANDLE driver_handle = INVALID_HANDLE_VALUE;
static int concurrent_usage = -1;
@@ -109,7 +109,7 @@ static int translate_driver_error(DWORD error)
}
}
-static int init_dllimports(void)
+static BOOL init_dllimports(void)
{
DLL_GET_HANDLE(ceusbkwrapper);
DLL_LOAD_FUNC(ceusbkwrapper, UkwOpenDriver, TRUE);
@@ -135,7 +135,7 @@ static int init_dllimports(void)
DLL_LOAD_FUNC(ceusbkwrapper, UkwIssueBulkTransfer, TRUE);
DLL_LOAD_FUNC(ceusbkwrapper, UkwIsPipeHalted, TRUE);
- return LIBUSB_SUCCESS;
+ return TRUE;
}
static void exit_dllimports(void)
@@ -186,11 +186,8 @@ static int wince_init(struct libusb_context *ctx)
// NB: concurrent usage supposes that init calls are equally balanced with
// exit calls. If init is called more than exit, we will not exit properly
if ( ++concurrent_usage == 0 ) { // First init?
- // Initialize pollable file descriptors
- init_polling();
-
// Load DLL imports
- if (init_dllimports() != LIBUSB_SUCCESS) {
+ if (!init_dllimports()) {
usbi_err(ctx, "could not resolve DLL functions");
r = LIBUSB_ERROR_NOT_SUPPORTED;
goto init_exit;
@@ -223,7 +220,6 @@ static int wince_init(struct libusb_context *ctx)
init_exit: // Holds semaphore here.
if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
exit_dllimports();
- exit_polling();
if (driver_handle != INVALID_HANDLE_VALUE) {
UkwCloseDriver(driver_handle);
@@ -239,10 +235,11 @@ init_exit: // Holds semaphore here.
return r;
}
-static void wince_exit(void)
+static void wince_exit(struct libusb_context *ctx)
{
HANDLE semaphore;
TCHAR sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
+ UNUSED(ctx);
_stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
semaphore = CreateSemaphore(NULL, 1, 1, sem_name);
@@ -259,7 +256,6 @@ static void wince_exit(void)
// Only works if exits and inits are balanced exactly
if (--concurrent_usage < 0) { // Last exit
exit_dllimports();
- exit_polling();
if (driver_handle != INVALID_HANDLE_VALUE) {
UkwCloseDriver(driver_handle);
@@ -328,7 +324,7 @@ static int wince_get_device_list(
}
new_devices = discovered_devs_append(new_devices, dev);
- if (!discdevs) {
+ if (!new_devices) {
r = LIBUSB_ERROR_NO_MEM;
goto err_out;
}
@@ -541,12 +537,9 @@ static void wince_destroy_device(struct libusb_device *dev)
static void wince_clear_transfer_priv(struct usbi_transfer *itransfer)
{
struct wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct winfd wfd = fd_to_winfd(transfer_priv->pollable_fd.fd);
- // No need to cancel transfer as it is either complete or abandoned
- wfd.itransfer = NULL;
- CloseHandle(wfd.handle);
- usbi_free_fd(&transfer_priv->pollable_fd);
+ usbi_close(transfer_priv->pollable_fd.fd);
+ transfer_priv->pollable_fd = INVALID_WINFD;
}
static int wince_cancel_transfer(struct usbi_transfer *itransfer)
@@ -570,11 +563,10 @@ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer
BOOL direction_in, ret;
struct winfd wfd;
DWORD flags;
- HANDLE eventHandle;
PUKW_CONTROL_HEADER setup = NULL;
const BOOL control_transfer = transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL;
+ int r;
- transfer_priv->pollable_fd = INVALID_WINFD;
if (control_transfer) {
setup = (PUKW_CONTROL_HEADER) transfer->buffer;
direction_in = setup->bmRequestType & LIBUSB_ENDPOINT_IN;
@@ -584,19 +576,18 @@ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer
flags = direction_in ? UKW_TF_IN_TRANSFER : UKW_TF_OUT_TRANSFER;
flags |= UKW_TF_SHORT_TRANSFER_OK;
- eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (eventHandle == NULL) {
- usbi_err(ctx, "Failed to create event for async transfer");
+ wfd = usbi_create_fd();
+ if (wfd.fd < 0)
return LIBUSB_ERROR_NO_MEM;
- }
- wfd = usbi_create_fd(eventHandle, direction_in ? RW_READ : RW_WRITE, itransfer, &wince_cancel_transfer);
- if (wfd.fd < 0) {
- CloseHandle(eventHandle);
- return LIBUSB_ERROR_NO_MEM;
+ r = usbi_add_pollfd(ctx, wfd.fd, direction_in ? POLLIN : POLLOUT);
+ if (r) {
+ usbi_close(wfd.fd);
+ return r;
}
transfer_priv->pollable_fd = wfd;
+
if (control_transfer) {
// Split out control setup header and data buffer
DWORD bufLen = transfer->length - sizeof(UKW_CONTROL_HEADER);
@@ -612,17 +603,14 @@ static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer
int libusbErr = translate_driver_error(GetLastError());
usbi_err(ctx, "UkwIssue%sTransfer failed: error %u",
control_transfer ? "Control" : "Bulk", (unsigned int)GetLastError());
- wince_clear_transfer_priv(itransfer);
+ usbi_remove_pollfd(ctx, wfd.fd);
+ usbi_close(wfd.fd);
+ transfer_priv->pollable_fd = INVALID_WINFD;
return libusbErr;
}
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? POLLIN : POLLOUT);
- return LIBUSB_SUCCESS;
-}
-static int wince_submit_iso_transfer(struct usbi_transfer *itransfer)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
+ return LIBUSB_SUCCESS;
}
static int wince_submit_transfer(struct usbi_transfer *itransfer)
@@ -635,7 +623,6 @@ static int wince_submit_transfer(struct usbi_transfer *itransfer)
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
return wince_submit_control_or_bulk_transfer(itransfer);
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- return wince_submit_iso_transfer(itransfer);
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
return LIBUSB_ERROR_NOT_SUPPORTED;
default:
@@ -763,7 +750,7 @@ static int wince_handle_events(
struct wince_transfer_priv* transfer_priv = NULL;
POLL_NFDS_TYPE i = 0;
BOOL found = FALSE;
- struct usbi_transfer *transfer;
+ struct usbi_transfer *itransfer;
DWORD io_size, io_result;
int r = LIBUSB_SUCCESS;
@@ -780,8 +767,8 @@ static int wince_handle_events(
// Because a Windows OVERLAPPED is used for poll emulation,
// a pollable fd is created and stored with each transfer
usbi_mutex_lock(&ctx->flying_transfers_lock);
- list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
- transfer_priv = usbi_transfer_get_os_priv(transfer);
+ list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+ transfer_priv = usbi_transfer_get_os_priv(itransfer);
if (transfer_priv->pollable_fd.fd == fds[i].fd) {
found = TRUE;
break;
@@ -796,7 +783,7 @@ static int wince_handle_events(
// let handle_callback free the event using the transfer wfd
// If you don't use the transfer wfd, you run a risk of trying to free a
// newly allocated wfd that took the place of the one from the transfer.
- wince_handle_callback(transfer, io_result, io_size);
+ wince_handle_callback(itransfer, io_result, io_size);
} else if (found) {
usbi_err(ctx, "matching transfer for fd %d has not completed", fds[i]);
r = LIBUSB_ERROR_OTHER;
@@ -848,11 +835,12 @@ static int wince_clock_gettime(int clk_id, struct timespec *tp)
}
}
-const struct usbi_os_backend wince_backend = {
+const struct usbi_os_backend usbi_backend = {
"Windows CE",
0,
wince_init,
wince_exit,
+ NULL, /* set_option() */
wince_get_device_list,
NULL, /* hotplug_poll */
@@ -893,6 +881,7 @@ const struct usbi_os_backend wince_backend = {
NULL, /* handle_transfer_completion() */
wince_clock_gettime,
+ 0,
sizeof(struct wince_device_priv),
0,
sizeof(struct wince_transfer_priv),
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/wince_usb.h
index edcb9fcc4..edcb9fcc4 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/wince_usb.h
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_common.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_common.h
index 55344ca26..b1725c2e3 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_common.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_common.h
@@ -68,31 +68,35 @@
/*
* Macros for handling DLL themselves
*/
+#define DLL_HANDLE_NAME(name) __dll_##name##_handle
+
#define DLL_DECLARE_HANDLE(name) \
- static HMODULE __dll_##name##_handle = NULL
+ static HMODULE DLL_HANDLE_NAME(name) = NULL
#define DLL_GET_HANDLE(name) \
do { \
- __dll_##name##_handle = DLL_LOAD_LIBRARY(name); \
- if (!__dll_##name##_handle) \
- return LIBUSB_ERROR_OTHER; \
+ DLL_HANDLE_NAME(name) = DLL_LOAD_LIBRARY(name); \
+ if (!DLL_HANDLE_NAME(name)) \
+ return FALSE; \
} while (0)
#define DLL_FREE_HANDLE(name) \
do { \
- if (__dll_##name##_handle) { \
- FreeLibrary(__dll_##name##_handle); \
- __dll_##name##_handle = NULL; \
+ if (DLL_HANDLE_NAME(name)) { \
+ FreeLibrary(DLL_HANDLE_NAME(name)); \
+ DLL_HANDLE_NAME(name) = NULL; \
} \
- } while(0)
+ } while (0)
/*
* Macros for handling functions within a DLL
*/
+#define DLL_FUNC_NAME(name) __dll_##name##_func_t
+
#define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args) \
- typedef ret (api * __dll_##name##_func_t)args; \
- static __dll_##name##_func_t prefixname = NULL
+ typedef ret (api * DLL_FUNC_NAME(name))args; \
+ static DLL_FUNC_NAME(name) prefixname = NULL
#define DLL_DECLARE_FUNC(api, ret, name, args) \
DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args)
@@ -101,22 +105,22 @@
#define DLL_LOAD_FUNC_PREFIXNAME(dll, prefixname, name, ret_on_failure) \
do { \
- HMODULE h = __dll_##dll##_handle; \
- prefixname = (__dll_##name##_func_t)GetProcAddress(h, \
+ HMODULE h = DLL_HANDLE_NAME(dll); \
+ prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
DLL_STRINGIFY(name)); \
if (prefixname) \
break; \
- prefixname = (__dll_##name##_func_t)GetProcAddress(h, \
+ prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
DLL_STRINGIFY(name) DLL_STRINGIFY(A)); \
if (prefixname) \
break; \
- prefixname = (__dll_##name##_func_t)GetProcAddress(h, \
+ prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
DLL_STRINGIFY(name) DLL_STRINGIFY(W)); \
if (prefixname) \
break; \
if (ret_on_failure) \
- return LIBUSB_ERROR_NOT_FOUND; \
- } while(0)
+ return FALSE; \
+ } while (0)
#define DLL_LOAD_FUNC(dll, name, ret_on_failure) \
DLL_LOAD_FUNC_PREFIXNAME(dll, name, name, ret_on_failure)
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.c
index d935394a6..92dbde5a8 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.c
@@ -32,6 +32,14 @@
#include "windows_common.h"
#include "windows_nt_common.h"
+// Public
+BOOL (WINAPI *pCancelIoEx)(HANDLE, LPOVERLAPPED);
+enum windows_version windows_version = WINDOWS_UNDEFINED;
+
+ // Global variables for init/exit
+static unsigned int init_count = 0;
+static bool usbdk_available = false;
+
// Global variables for clock_gettime mechanism
static uint64_t hires_ticks_to_ps;
static uint64_t hires_frequency;
@@ -50,6 +58,11 @@ struct timer_request {
static HANDLE timer_thread = NULL;
static DWORD timer_thread_id = 0;
+/* Kernel32 dependencies */
+DLL_DECLARE_HANDLE(Kernel32);
+/* This call is only available from XP SP2 */
+DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, IsWow64Process, (HANDLE, PBOOL));
+
/* User32 dependencies */
DLL_DECLARE_HANDLE(User32);
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, GetMessageA, (LPMSG, HWND, UINT, UINT));
@@ -111,6 +124,11 @@ const char *windows_error_str(DWORD error_code)
}
#endif
+static inline struct windows_context_priv *_context_priv(struct libusb_context *ctx)
+{
+ return (struct windows_context_priv *)ctx->os_priv;
+}
+
/* Hash table functions - modified From glibc 2.3.2:
[Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
[Knuth] The Art of Computer Programming, part 3 (6.4) */
@@ -123,7 +141,7 @@ typedef struct htab_entry {
} htab_entry;
static htab_entry *htab_table = NULL;
-static usbi_mutex_t htab_mutex = NULL;
+static usbi_mutex_t htab_mutex;
static unsigned long htab_filled;
/* Before using the hash table we must allocate memory for it.
@@ -256,35 +274,46 @@ out_unlock:
return idx;
}
-static int windows_init_dlls(void)
+/*
+* Make a transfer complete synchronously
+*/
+void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size)
+{
+ overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
+ overlapped->InternalHigh = size;
+ SetEvent(overlapped->hEvent);
+}
+
+static BOOL windows_init_dlls(void)
{
+ DLL_GET_HANDLE(Kernel32);
+ DLL_LOAD_FUNC_PREFIXED(Kernel32, p, IsWow64Process, FALSE);
+ pCancelIoEx = (BOOL (WINAPI *)(HANDLE, LPOVERLAPPED))
+ GetProcAddress(DLL_HANDLE_NAME(Kernel32), "CancelIoEx");
+ usbi_dbg("Will use CancelIo%s for I/O cancellation", pCancelIoEx ? "Ex" : "");
+
DLL_GET_HANDLE(User32);
DLL_LOAD_FUNC_PREFIXED(User32, p, GetMessageA, TRUE);
DLL_LOAD_FUNC_PREFIXED(User32, p, PeekMessageA, TRUE);
DLL_LOAD_FUNC_PREFIXED(User32, p, PostThreadMessageA, TRUE);
- return LIBUSB_SUCCESS;
+ return TRUE;
}
static void windows_exit_dlls(void)
{
+ DLL_FREE_HANDLE(Kernel32);
DLL_FREE_HANDLE(User32);
}
static bool windows_init_clock(struct libusb_context *ctx)
{
DWORD_PTR affinity, dummy;
- HANDLE event = NULL;
+ HANDLE event;
LARGE_INTEGER li_frequency;
int i;
if (QueryPerformanceFrequency(&li_frequency)) {
- // Load DLL imports
- if (windows_init_dlls() != LIBUSB_SUCCESS) {
- usbi_err(ctx, "could not resolve DLL functions");
- return false;
- }
-
// The hires frequency can go as high as 4 GHz, so we'll use a conversion
// to picoseconds to compute the tv_nsecs part in clock_gettime
hires_frequency = li_frequency.QuadPart;
@@ -340,7 +369,7 @@ static bool windows_init_clock(struct libusb_context *ctx)
return true;
}
-void windows_destroy_clock(void)
+static void windows_destroy_clock(void)
{
if (timer_thread) {
// actually the signal to quit the thread.
@@ -357,6 +386,110 @@ void windows_destroy_clock(void)
}
}
+/* Windows version detection */
+static BOOL is_x64(void)
+{
+ BOOL ret = FALSE;
+
+ // Detect if we're running a 32 or 64 bit system
+ if (sizeof(uintptr_t) < 8) {
+ if (pIsWow64Process != NULL)
+ pIsWow64Process(GetCurrentProcess(), &ret);
+ } else {
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+static void get_windows_version(void)
+{
+ OSVERSIONINFOEXA vi, vi2;
+ const char *arch, *w = NULL;
+ unsigned major, minor, version;
+ ULONGLONG major_equal, minor_equal;
+ BOOL ws;
+
+ windows_version = WINDOWS_UNDEFINED;
+
+ memset(&vi, 0, sizeof(vi));
+ vi.dwOSVersionInfoSize = sizeof(vi);
+ if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
+ memset(&vi, 0, sizeof(vi));
+ vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
+ if (!GetVersionExA((OSVERSIONINFOA *)&vi))
+ return;
+ }
+
+ if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
+ return;
+
+ if ((vi.dwMajorVersion > 6) || ((vi.dwMajorVersion == 6) && (vi.dwMinorVersion >= 2))) {
+ // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version
+ // See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
+
+ major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
+ for (major = vi.dwMajorVersion; major <= 9; major++) {
+ memset(&vi2, 0, sizeof(vi2));
+ vi2.dwOSVersionInfoSize = sizeof(vi2);
+ vi2.dwMajorVersion = major;
+ if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal))
+ continue;
+
+ if (vi.dwMajorVersion < major) {
+ vi.dwMajorVersion = major;
+ vi.dwMinorVersion = 0;
+ }
+
+ minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
+ for (minor = vi.dwMinorVersion; minor <= 9; minor++) {
+ memset(&vi2, 0, sizeof(vi2));
+ vi2.dwOSVersionInfoSize = sizeof(vi2);
+ vi2.dwMinorVersion = minor;
+ if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal))
+ continue;
+
+ vi.dwMinorVersion = minor;
+ break;
+ }
+
+ break;
+ }
+ }
+
+ if ((vi.dwMajorVersion > 0xf) || (vi.dwMinorVersion > 0xf))
+ return;
+
+ ws = (vi.wProductType <= VER_NT_WORKSTATION);
+ version = vi.dwMajorVersion << 4 | vi.dwMinorVersion;
+ switch (version) {
+ case 0x50: windows_version = WINDOWS_2000; w = "2000"; break;
+ case 0x51: windows_version = WINDOWS_XP; w = "XP"; break;
+ case 0x52: windows_version = WINDOWS_2003; w = "2003"; break;
+ case 0x60: windows_version = WINDOWS_VISTA; w = (ws ? "Vista" : "2008"); break;
+ case 0x61: windows_version = WINDOWS_7; w = (ws ? "7" : "2008_R2"); break;
+ case 0x62: windows_version = WINDOWS_8; w = (ws ? "8" : "2012"); break;
+ case 0x63: windows_version = WINDOWS_8_1; w = (ws ? "8.1" : "2012_R2"); break;
+ case 0x64: windows_version = WINDOWS_10; w = (ws ? "10" : "2016"); break;
+ default:
+ if (version < 0x50) {
+ return;
+ } else {
+ windows_version = WINDOWS_11_OR_LATER;
+ w = "11 or later";
+ }
+ }
+
+ arch = is_x64() ? "64-bit" : "32-bit";
+
+ if (vi.wServicePackMinor)
+ usbi_dbg("Windows %s SP%u.%u %s", w, vi.wServicePackMajor, vi.wServicePackMinor, arch);
+ else if (vi.wServicePackMajor)
+ usbi_dbg("Windows %s SP%u %s", w, vi.wServicePackMajor, arch);
+ else
+ usbi_dbg("Windows %s %s", w, arch);
+}
+
/*
* Monotonic and real time functions
*/
@@ -401,74 +534,16 @@ static unsigned __stdcall windows_clock_gettime_threaded(void *param)
}
}
-int windows_clock_gettime(int clk_id, struct timespec *tp)
-{
- struct timer_request request;
-#if !defined(_MSC_VER) || (_MSC_VER < 1900)
- FILETIME filetime;
- ULARGE_INTEGER rtime;
-#endif
- DWORD r;
-
- switch (clk_id) {
- case USBI_CLOCK_MONOTONIC:
- if (timer_thread) {
- request.tp = tp;
- request.event = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (request.event == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_REQUEST, 0, (LPARAM)&request)) {
- usbi_err(NULL, "PostThreadMessage failed for timer thread: %s", windows_error_str(0));
- CloseHandle(request.event);
- return LIBUSB_ERROR_OTHER;
- }
-
- do {
- r = WaitForSingleObject(request.event, TIMER_REQUEST_RETRY_MS);
- if (r == WAIT_TIMEOUT)
- usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
- else if (r == WAIT_FAILED)
- usbi_err(NULL, "WaitForSingleObject failed: %s", windows_error_str(0));
- } while (r == WAIT_TIMEOUT);
- CloseHandle(request.event);
-
- if (r == WAIT_OBJECT_0)
- return LIBUSB_SUCCESS;
- else
- return LIBUSB_ERROR_OTHER;
- }
- // Fall through and return real-time if monotonic was not detected @ timer init
- case USBI_CLOCK_REALTIME:
-#if defined(_MSC_VER) && (_MSC_VER >= 1900)
- timespec_get(tp, TIME_UTC);
-#else
- // We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
- // with a predef epoch time to have an epoch that starts at 1970.01.01 00:00
- // Note however that our resolution is bounded by the Windows system time
- // functions and is at best of the order of 1 ms (or, usually, worse)
- GetSystemTimeAsFileTime(&filetime);
- rtime.LowPart = filetime.dwLowDateTime;
- rtime.HighPart = filetime.dwHighDateTime;
- rtime.QuadPart -= EPOCH_TIME;
- tp->tv_sec = (long)(rtime.QuadPart / 10000000);
- tp->tv_nsec = (long)((rtime.QuadPart % 10000000) * 100);
-#endif
- return LIBUSB_SUCCESS;
- default:
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-}
-
-static void windows_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
+static void windows_transfer_callback(const struct windows_backend *backend,
+ struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size)
{
int status, istatus;
- usbi_dbg("handling I/O completion with errcode %u, size %u", io_result, io_size);
+ usbi_dbg("handling I/O completion with errcode %u, size %u", (unsigned int)io_result, (unsigned int)io_size);
switch (io_result) {
case NO_ERROR:
- status = windows_copy_transfer_data(itransfer, io_size);
+ status = backend->copy_transfer_data(itransfer, (uint32_t)io_size);
break;
case ERROR_GEN_FAILURE:
usbi_dbg("detected endpoint stall");
@@ -479,26 +554,31 @@ static void windows_transfer_callback(struct usbi_transfer *itransfer, uint32_t
status = LIBUSB_TRANSFER_TIMED_OUT;
break;
case ERROR_OPERATION_ABORTED:
- istatus = windows_copy_transfer_data(itransfer, io_size);
+ istatus = backend->copy_transfer_data(itransfer, (uint32_t)io_size);
if (istatus != LIBUSB_TRANSFER_COMPLETED)
usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus);
usbi_dbg("detected operation aborted");
status = LIBUSB_TRANSFER_CANCELLED;
break;
+ case ERROR_FILE_NOT_FOUND:
+ usbi_dbg("detected device removed");
+ status = LIBUSB_TRANSFER_NO_DEVICE;
+ break;
default:
- usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %u: %s", io_result, windows_error_str(io_result));
+ usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %u: %s", (unsigned int)io_result, windows_error_str(io_result));
status = LIBUSB_TRANSFER_ERROR;
break;
}
- windows_clear_transfer_priv(itransfer); // Cancel polling
+ backend->clear_transfer_priv(itransfer); // Cancel polling
if (status == LIBUSB_TRANSFER_CANCELLED)
usbi_handle_transfer_cancellation(itransfer);
else
usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
}
-void windows_handle_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
+static void windows_handle_callback(const struct windows_backend *backend,
+ struct usbi_transfer *itransfer, DWORD io_result, DWORD io_size)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
@@ -507,7 +587,7 @@ void windows_handle_callback(struct usbi_transfer *itransfer, uint32_t io_result
case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- windows_transfer_callback(itransfer, io_result, io_size);
+ windows_transfer_callback(backend, itransfer, io_result, io_size);
break;
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
usbi_warn(ITRANSFER_CTX(itransfer), "bulk stream transfers are not yet supported on this platform");
@@ -517,13 +597,269 @@ void windows_handle_callback(struct usbi_transfer *itransfer, uint32_t io_result
}
}
-int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
+static int windows_init(struct libusb_context *ctx)
{
- POLL_NFDS_TYPE i;
- bool found = false;
- struct usbi_transfer *transfer;
- struct winfd *pollable_fd = NULL;
+ struct windows_context_priv *priv = _context_priv(ctx);
+ HANDLE semaphore;
+ char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
+ int r = LIBUSB_ERROR_OTHER;
+ bool winusb_backend_init = false;
+
+ sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
+ semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
+ if (semaphore == NULL) {
+ usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ // A successful wait brings our semaphore count to 0 (unsignaled)
+ // => any concurent wait stalls until the semaphore's release
+ if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
+ usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0));
+ CloseHandle(semaphore);
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ // NB: concurrent usage supposes that init calls are equally balanced with
+ // exit calls. If init is called more than exit, we will not exit properly
+ if (++init_count == 1) { // First init?
+ // Load DLL imports
+ if (!windows_init_dlls()) {
+ usbi_err(ctx, "could not resolve DLL functions");
+ goto init_exit;
+ }
+
+ get_windows_version();
+
+ if (windows_version == WINDOWS_UNDEFINED) {
+ usbi_err(ctx, "failed to detect Windows version");
+ r = LIBUSB_ERROR_NOT_SUPPORTED;
+ goto init_exit;
+ }
+
+ if (!windows_init_clock(ctx))
+ goto init_exit;
+
+ if (!htab_create(ctx))
+ goto init_exit;
+
+ r = winusb_backend.init(ctx);
+ if (r != LIBUSB_SUCCESS)
+ goto init_exit;
+ winusb_backend_init = true;
+
+ r = usbdk_backend.init(ctx);
+ if (r == LIBUSB_SUCCESS) {
+ usbi_dbg("UsbDk backend is available");
+ usbdk_available = true;
+ } else {
+ usbi_info(ctx, "UsbDk backend is not available");
+ // Do not report this as an error
+ r = LIBUSB_SUCCESS;
+ }
+ }
+
+ // By default, new contexts will use the WinUSB backend
+ priv->backend = &winusb_backend;
+
+ r = LIBUSB_SUCCESS;
+
+init_exit: // Holds semaphore here
+ if ((init_count == 1) && (r != LIBUSB_SUCCESS)) { // First init failed?
+ if (winusb_backend_init)
+ winusb_backend.exit(ctx);
+ htab_destroy();
+ windows_destroy_clock();
+ windows_exit_dlls();
+ --init_count;
+ }
+
+ ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
+ CloseHandle(semaphore);
+ return r;
+}
+
+static void windows_exit(struct libusb_context *ctx)
+{
+ HANDLE semaphore;
+ char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
+ UNUSED(ctx);
+
+ sprintf(sem_name, "libusb_init%08X", (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
+ semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
+ if (semaphore == NULL)
+ return;
+
+ // A successful wait brings our semaphore count to 0 (unsignaled)
+ // => any concurent wait stalls until the semaphore release
+ if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
+ CloseHandle(semaphore);
+ return;
+ }
+
+ // Only works if exits and inits are balanced exactly
+ if (--init_count == 0) { // Last exit
+ if (usbdk_available) {
+ usbdk_backend.exit(ctx);
+ usbdk_available = false;
+ }
+ winusb_backend.exit(ctx);
+ htab_destroy();
+ windows_destroy_clock();
+ windows_exit_dlls();
+ }
+
+ ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
+ CloseHandle(semaphore);
+}
+
+static int windows_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap)
+{
+ struct windows_context_priv *priv = _context_priv(ctx);
+
+ UNUSED(ap);
+
+ switch (option) {
+ case LIBUSB_OPTION_USE_USBDK:
+ if (usbdk_available) {
+ usbi_dbg("switching context %p to use UsbDk backend", ctx);
+ priv->backend = &usbdk_backend;
+ } else {
+ usbi_err(ctx, "UsbDk backend not available");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+ return LIBUSB_SUCCESS;
+ default:
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ }
+
+}
+
+static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs)
+{
+ struct windows_context_priv *priv = _context_priv(ctx);
+ return priv->backend->get_device_list(ctx, discdevs);
+}
+
+static int windows_open(struct libusb_device_handle *dev_handle)
+{
+ struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
+ return priv->backend->open(dev_handle);
+}
+
+static void windows_close(struct libusb_device_handle *dev_handle)
+{
+ struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
+ priv->backend->close(dev_handle);
+}
+
+static int windows_get_device_descriptor(struct libusb_device *dev,
+ unsigned char *buffer, int *host_endian)
+{
+ struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
+ *host_endian = 0;
+ return priv->backend->get_device_descriptor(dev, buffer);
+}
+
+static int windows_get_active_config_descriptor(struct libusb_device *dev,
+ unsigned char *buffer, size_t len, int *host_endian)
+{
+ struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
+ *host_endian = 0;
+ return priv->backend->get_active_config_descriptor(dev, buffer, len);
+}
+
+static int windows_get_config_descriptor(struct libusb_device *dev,
+ uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
+{
+ struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
+ *host_endian = 0;
+ return priv->backend->get_config_descriptor(dev, config_index, buffer, len);
+}
+
+static int windows_get_config_descriptor_by_value(struct libusb_device *dev,
+ uint8_t bConfigurationValue, unsigned char **buffer, int *host_endian)
+{
+ struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
+ *host_endian = 0;
+ return priv->backend->get_config_descriptor_by_value(dev, bConfigurationValue, buffer);
+}
+
+static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config)
+{
+ struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
+ return priv->backend->get_configuration(dev_handle, config);
+}
+
+static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config)
+{
+ struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
+ return priv->backend->set_configuration(dev_handle, config);
+}
+
+static int windows_claim_interface(struct libusb_device_handle *dev_handle, int interface_number)
+{
+ struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
+ return priv->backend->claim_interface(dev_handle, interface_number);
+}
+
+static int windows_release_interface(struct libusb_device_handle *dev_handle, int interface_number)
+{
+ struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
+ return priv->backend->release_interface(dev_handle, interface_number);
+}
+
+static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle,
+ int interface_number, int altsetting)
+{
+ struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
+ return priv->backend->set_interface_altsetting(dev_handle, interface_number, altsetting);
+}
+
+static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
+{
+ struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
+ return priv->backend->clear_halt(dev_handle, endpoint);
+}
+
+static int windows_reset_device(struct libusb_device_handle *dev_handle)
+{
+ struct windows_context_priv *priv = _context_priv(HANDLE_CTX(dev_handle));
+ return priv->backend->reset_device(dev_handle);
+}
+
+static void windows_destroy_device(struct libusb_device *dev)
+{
+ struct windows_context_priv *priv = _context_priv(DEVICE_CTX(dev));
+ priv->backend->destroy_device(dev);
+}
+
+static int windows_submit_transfer(struct usbi_transfer *itransfer)
+{
+ struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
+ return priv->backend->submit_transfer(itransfer);
+}
+
+static int windows_cancel_transfer(struct usbi_transfer *itransfer)
+{
+ struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
+ return priv->backend->cancel_transfer(itransfer);
+}
+
+static void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
+{
+ struct windows_context_priv *priv = _context_priv(ITRANSFER_CTX(itransfer));
+ priv->backend->clear_transfer_priv(itransfer);
+}
+
+static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
+{
+ struct windows_context_priv *priv = _context_priv(ctx);
+ struct usbi_transfer *itransfer;
DWORD io_size, io_result;
+ POLL_NFDS_TYPE i;
+ bool found;
+ int transfer_fd;
int r = LIBUSB_SUCCESS;
usbi_mutex_lock(&ctx->open_devs_lock);
@@ -538,11 +874,12 @@ int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_N
// Because a Windows OVERLAPPED is used for poll emulation,
// a pollable fd is created and stored with each transfer
- usbi_mutex_lock(&ctx->flying_transfers_lock);
found = false;
- list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
- pollable_fd = windows_get_fd(transfer);
- if (pollable_fd->fd == fds[i].fd) {
+ transfer_fd = -1;
+ usbi_mutex_lock(&ctx->flying_transfers_lock);
+ list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+ transfer_fd = priv->backend->get_transfer_fd(itransfer);
+ if (transfer_fd == fds[i].fd) {
found = true;
break;
}
@@ -550,15 +887,16 @@ int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_N
usbi_mutex_unlock(&ctx->flying_transfers_lock);
if (found) {
- windows_get_overlapped_result(transfer, pollable_fd, &io_result, &io_size);
+ priv->backend->get_overlapped_result(itransfer, &io_result, &io_size);
+
+ usbi_remove_pollfd(ctx, transfer_fd);
- usbi_remove_pollfd(ctx, pollable_fd->fd);
// let handle_callback free the event using the transfer wfd
// If you don't use the transfer wfd, you run a risk of trying to free a
// newly allocated wfd that took the place of the one from the transfer.
- windows_handle_callback(transfer, io_result, io_size);
+ windows_handle_callback(priv->backend, itransfer, io_result, io_size);
} else {
- usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i]);
+ usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i].fd);
r = LIBUSB_ERROR_NOT_FOUND;
break;
}
@@ -568,24 +906,103 @@ int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_N
return r;
}
-int windows_common_init(struct libusb_context *ctx)
+static int windows_clock_gettime(int clk_id, struct timespec *tp)
{
- if (!windows_init_clock(ctx))
- goto error_roll_back;
+ struct timer_request request;
+#if !defined(_MSC_VER) || (_MSC_VER < 1900)
+ FILETIME filetime;
+ ULARGE_INTEGER rtime;
+#endif
+ DWORD r;
- if (!htab_create(ctx))
- goto error_roll_back;
+ switch (clk_id) {
+ case USBI_CLOCK_MONOTONIC:
+ if (timer_thread) {
+ request.tp = tp;
+ request.event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (request.event == NULL)
+ return LIBUSB_ERROR_NO_MEM;
- return LIBUSB_SUCCESS;
+ if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_REQUEST, 0, (LPARAM)&request)) {
+ usbi_err(NULL, "PostThreadMessage failed for timer thread: %s", windows_error_str(0));
+ CloseHandle(request.event);
+ return LIBUSB_ERROR_OTHER;
+ }
-error_roll_back:
- windows_common_exit();
- return LIBUSB_ERROR_NO_MEM;
-}
+ do {
+ r = WaitForSingleObject(request.event, TIMER_REQUEST_RETRY_MS);
+ if (r == WAIT_TIMEOUT)
+ usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
+ else if (r == WAIT_FAILED)
+ usbi_err(NULL, "WaitForSingleObject failed: %s", windows_error_str(0));
+ } while (r == WAIT_TIMEOUT);
+ CloseHandle(request.event);
-void windows_common_exit(void)
-{
- htab_destroy();
- windows_destroy_clock();
- windows_exit_dlls();
+ if (r == WAIT_OBJECT_0)
+ return LIBUSB_SUCCESS;
+ else
+ return LIBUSB_ERROR_OTHER;
+ }
+ // Fall through and return real-time if monotonic was not detected @ timer init
+ case USBI_CLOCK_REALTIME:
+#if defined(_MSC_VER) && (_MSC_VER >= 1900)
+ timespec_get(tp, TIME_UTC);
+#else
+ // We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
+ // with a predef epoch time to have an epoch that starts at 1970.01.01 00:00
+ // Note however that our resolution is bounded by the Windows system time
+ // functions and is at best of the order of 1 ms (or, usually, worse)
+ GetSystemTimeAsFileTime(&filetime);
+ rtime.LowPart = filetime.dwLowDateTime;
+ rtime.HighPart = filetime.dwHighDateTime;
+ rtime.QuadPart -= EPOCH_TIME;
+ tp->tv_sec = (long)(rtime.QuadPart / 10000000);
+ tp->tv_nsec = (long)((rtime.QuadPart % 10000000) * 100);
+#endif
+ return LIBUSB_SUCCESS;
+ default:
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
}
+
+// NB: MSVC6 does not support named initializers.
+const struct usbi_os_backend usbi_backend = {
+ "Windows",
+ USBI_CAP_HAS_HID_ACCESS,
+ windows_init,
+ windows_exit,
+ windows_set_option,
+ windows_get_device_list,
+ NULL, /* hotplug_poll */
+ windows_open,
+ windows_close,
+ windows_get_device_descriptor,
+ windows_get_active_config_descriptor,
+ windows_get_config_descriptor,
+ windows_get_config_descriptor_by_value,
+ windows_get_configuration,
+ windows_set_configuration,
+ windows_claim_interface,
+ windows_release_interface,
+ windows_set_interface_altsetting,
+ windows_clear_halt,
+ windows_reset_device,
+ NULL, /* alloc_streams */
+ NULL, /* free_streams */
+ NULL, /* dev_mem_alloc */
+ NULL, /* dev_mem_free */
+ NULL, /* kernel_driver_active */
+ NULL, /* detach_kernel_driver */
+ NULL, /* attach_kernel_driver */
+ windows_destroy_device,
+ windows_submit_transfer,
+ windows_cancel_transfer,
+ windows_clear_transfer_priv,
+ windows_handle_events,
+ NULL, /* handle_transfer_completion */
+ windows_clock_gettime,
+ sizeof(struct windows_context_priv),
+ sizeof(union windows_device_priv),
+ sizeof(union windows_device_handle_priv),
+ sizeof(union windows_transfer_priv),
+};
diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.h
new file mode 100644
index 000000000..e155b5d3e
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_common.h
@@ -0,0 +1,110 @@
+/*
+ * Windows backend common header for libusb 1.0
+ *
+ * This file brings together header code common between
+ * the desktop Windows backends.
+ * Copyright © 2012-2013 RealVNC Ltd.
+ * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
+ * With contributions from Michael Plante, Orin Eman et al.
+ * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
+ * Major code testing contribution by Xiaofan Chen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include "windows_nt_shared_types.h"
+
+ /* Windows versions */
+enum windows_version {
+ WINDOWS_UNDEFINED,
+ WINDOWS_2000,
+ WINDOWS_XP,
+ WINDOWS_2003, // Also XP x64
+ WINDOWS_VISTA,
+ WINDOWS_7,
+ WINDOWS_8,
+ WINDOWS_8_1,
+ WINDOWS_10,
+ WINDOWS_11_OR_LATER
+};
+
+extern enum windows_version windows_version;
+
+/* This call is only available from Vista */
+extern BOOL (WINAPI *pCancelIoEx)(HANDLE, LPOVERLAPPED);
+
+struct windows_backend {
+ int (*init)(struct libusb_context *ctx);
+ void (*exit)(struct libusb_context *ctx);
+ int (*get_device_list)(struct libusb_context *ctx,
+ struct discovered_devs **discdevs);
+ int (*open)(struct libusb_device_handle *dev_handle);
+ void (*close)(struct libusb_device_handle *dev_handle);
+ int (*get_device_descriptor)(struct libusb_device *device, unsigned char *buffer);
+ int (*get_active_config_descriptor)(struct libusb_device *device,
+ unsigned char *buffer, size_t len);
+ int (*get_config_descriptor)(struct libusb_device *device,
+ uint8_t config_index, unsigned char *buffer, size_t len);
+ int (*get_config_descriptor_by_value)(struct libusb_device *device,
+ uint8_t bConfigurationValue, unsigned char **buffer);
+ int (*get_configuration)(struct libusb_device_handle *dev_handle, int *config);
+ int (*set_configuration)(struct libusb_device_handle *dev_handle, int config);
+ int (*claim_interface)(struct libusb_device_handle *dev_handle, int interface_number);
+ int (*release_interface)(struct libusb_device_handle *dev_handle, int interface_number);
+ int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle,
+ int interface_number, int altsetting);
+ int (*clear_halt)(struct libusb_device_handle *dev_handle,
+ unsigned char endpoint);
+ int (*reset_device)(struct libusb_device_handle *dev_handle);
+ void (*destroy_device)(struct libusb_device *dev);
+ int (*submit_transfer)(struct usbi_transfer *itransfer);
+ int (*cancel_transfer)(struct usbi_transfer *itransfer);
+ void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
+ int (*copy_transfer_data)(struct usbi_transfer *itransfer, uint32_t io_size);
+ int (*get_transfer_fd)(struct usbi_transfer *itransfer);
+ void (*get_overlapped_result)(struct usbi_transfer *itransfer,
+ DWORD *io_result, DWORD *io_size);
+};
+
+struct windows_context_priv {
+ const struct windows_backend *backend;
+};
+
+union windows_device_priv {
+ struct usbdk_device_priv usbdk_priv;
+ struct winusb_device_priv winusb_priv;
+};
+
+union windows_device_handle_priv {
+ struct usbdk_device_handle_priv usbdk_priv;
+ struct winusb_device_handle_priv winusb_priv;
+};
+
+union windows_transfer_priv {
+ struct usbdk_transfer_priv usbdk_priv;
+ struct winusb_transfer_priv winusb_priv;
+};
+
+extern const struct windows_backend usbdk_backend;
+extern const struct windows_backend winusb_backend;
+
+unsigned long htab_hash(const char *str);
+void windows_force_sync_completion(OVERLAPPED *overlapped, ULONG size);
+
+#if defined(ENABLE_LOGGING)
+const char *windows_error_str(DWORD error_code);
+#endif
diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_shared_types.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_shared_types.h
new file mode 100644
index 000000000..68bf261d5
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_nt_shared_types.h
@@ -0,0 +1,138 @@
+#pragma once
+
+#include "windows_common.h"
+
+#include <pshpack1.h>
+
+typedef struct USB_DEVICE_DESCRIPTOR {
+ UCHAR bLength;
+ UCHAR bDescriptorType;
+ USHORT bcdUSB;
+ UCHAR bDeviceClass;
+ UCHAR bDeviceSubClass;
+ UCHAR bDeviceProtocol;
+ UCHAR bMaxPacketSize0;
+ USHORT idVendor;
+ USHORT idProduct;
+ USHORT bcdDevice;
+ UCHAR iManufacturer;
+ UCHAR iProduct;
+ UCHAR iSerialNumber;
+ UCHAR bNumConfigurations;
+} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
+
+typedef struct USB_CONFIGURATION_DESCRIPTOR {
+ UCHAR bLength;
+ UCHAR bDescriptorType;
+ USHORT wTotalLength;
+ UCHAR bNumInterfaces;
+ UCHAR bConfigurationValue;
+ UCHAR iConfiguration;
+ UCHAR bmAttributes;
+ UCHAR MaxPower;
+} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
+
+#include <poppack.h>
+
+#define MAX_DEVICE_ID_LEN 200
+
+typedef struct USB_DK_DEVICE_ID {
+ WCHAR DeviceID[MAX_DEVICE_ID_LEN];
+ WCHAR InstanceID[MAX_DEVICE_ID_LEN];
+} USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID;
+
+typedef struct USB_DK_DEVICE_INFO {
+ USB_DK_DEVICE_ID ID;
+ ULONG64 FilterID;
+ ULONG64 Port;
+ ULONG64 Speed;
+ USB_DEVICE_DESCRIPTOR DeviceDescriptor;
+} USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO;
+
+typedef struct USB_DK_ISO_TRANSFER_RESULT {
+ ULONG64 ActualLength;
+ ULONG64 TransferResult;
+} USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT;
+
+typedef struct USB_DK_GEN_TRANSFER_RESULT {
+ ULONG64 BytesTransferred;
+ ULONG64 UsbdStatus; // USBD_STATUS code
+} USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT;
+
+typedef struct USB_DK_TRANSFER_RESULT {
+ USB_DK_GEN_TRANSFER_RESULT GenResult;
+ PVOID64 IsochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT
+} USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT;
+
+typedef struct USB_DK_TRANSFER_REQUEST {
+ ULONG64 EndpointAddress;
+ PVOID64 Buffer;
+ ULONG64 BufferLength;
+ ULONG64 TransferType;
+ ULONG64 IsochronousPacketsArraySize;
+ PVOID64 IsochronousPacketsArray;
+ USB_DK_TRANSFER_RESULT Result;
+} USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST;
+
+struct usbdk_device_priv {
+ USB_DK_DEVICE_INFO info;
+ PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
+ HANDLE redirector_handle;
+ HANDLE system_handle;
+ uint8_t active_configuration;
+};
+
+struct winusb_device_priv {
+ bool initialized;
+ bool root_hub;
+ uint8_t active_config;
+ uint8_t depth; // distance to HCD
+ const struct windows_usb_api_backend *apib;
+ char *dev_id;
+ char *path; // device interface path
+ int sub_api; // for WinUSB-like APIs
+ struct {
+ char *path; // each interface needs a device interface path,
+ const struct windows_usb_api_backend *apib; // an API backend (multiple drivers support),
+ int sub_api;
+ int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
+ uint8_t *endpoint;
+ bool restricted_functionality; // indicates if the interface functionality is restricted
+ // by Windows (eg. HID keyboards or mice cannot do R/W)
+ } usb_interface[USB_MAXINTERFACES];
+ struct hid_device_priv *hid;
+ USB_DEVICE_DESCRIPTOR dev_descriptor;
+ PUSB_CONFIGURATION_DESCRIPTOR *config_descriptor; // list of pointers to the cached config descriptors
+};
+
+struct usbdk_device_handle_priv {
+ // Not currently used
+ char dummy;
+};
+
+struct winusb_device_handle_priv {
+ int active_interface;
+ struct {
+ HANDLE dev_handle; // WinUSB needs an extra handle for the file
+ HANDLE api_handle; // used by the API to communicate with the device
+ } interface_handle[USB_MAXINTERFACES];
+ int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
+};
+
+struct usbdk_transfer_priv {
+ USB_DK_TRANSFER_REQUEST request;
+ struct winfd pollable_fd;
+ HANDLE system_handle;
+ PULONG64 IsochronousPacketsArray;
+ PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
+};
+
+struct winusb_transfer_priv {
+ struct winfd pollable_fd;
+ HANDLE handle;
+ uint8_t interface_number;
+ uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID
+ uint8_t *hid_dest; // transfer buffer destination, required for HID
+ size_t hid_expected_size;
+ void *iso_context;
+};
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_usbdk.c
index 7cc579387..fbccbd5cf 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_usbdk.c
@@ -23,22 +23,12 @@
#include <config.h>
-#if defined(USE_USBDK)
-
#include <windows.h>
-#include <cfgmgr32.h>
#include <stdio.h>
#include "libusbi.h"
#include "windows_common.h"
#include "windows_nt_common.h"
-
-#define ULONG64 uint64_t
-#define PVOID64 uint64_t
-
-typedef CONST WCHAR *PCWCHAR;
-#define wcsncpy_s wcsncpy
-
#include "windows_usbdk.h"
#if !defined(STATUS_SUCCESS)
@@ -55,7 +45,7 @@ typedef LONG NTSTATUS;
#endif
#if !defined(USBD_SUCCESS)
-typedef int32_t USBD_STATUS;
+typedef LONG USBD_STATUS;
#define USBD_SUCCESS(Status) ((USBD_STATUS) (Status) >= 0)
#define USBD_PENDING(Status) ((ULONG) (Status) >> 30 == 1)
#define USBD_ERROR(Status) ((USBD_STATUS) (Status) < 0)
@@ -66,22 +56,6 @@ typedef int32_t USBD_STATUS;
#define USBD_STATUS_CANCELED ((USBD_STATUS) 0xc0010000)
#endif
-static int concurrent_usage = -1;
-
-struct usbdk_device_priv {
- USB_DK_DEVICE_INFO info;
- PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
- HANDLE redirector_handle;
- uint8_t active_configuration;
-};
-
-struct usbdk_transfer_priv {
- USB_DK_TRANSFER_REQUEST request;
- struct winfd pollable_fd;
- PULONG64 IsochronousPacketsArray;
- PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
-};
-
static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev)
{
return (struct usbdk_device_priv *)dev->os_priv;
@@ -115,7 +89,7 @@ static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
if (api_ptr == NULL)
- usbi_err(ctx, "UsbDkHelper API %s not found, error %d", api_name, GetLastError());
+ usbi_err(ctx, "UsbDkHelper API %s not found: %s", api_name, windows_error_str(0));
return api_ptr;
}
@@ -132,7 +106,7 @@ static int load_usbdk_helper_dll(struct libusb_context *ctx)
{
usbdk_helper.module = LoadLibraryA("UsbDkHelper");
if (usbdk_helper.module == NULL) {
- usbi_err(ctx, "Failed to load UsbDkHelper.dll, error %d", GetLastError());
+ usbi_err(ctx, "Failed to load UsbDkHelper.dll: %s", windows_error_str(0));
return LIBUSB_ERROR_NOT_FOUND;
}
@@ -198,41 +172,41 @@ error_unload:
static int usbdk_init(struct libusb_context *ctx)
{
- int r;
+ SC_HANDLE managerHandle;
+ SC_HANDLE serviceHandle;
- if (++concurrent_usage == 0) { // First init?
- r = load_usbdk_helper_dll(ctx);
- if (r)
- goto init_exit;
+ managerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+ if (managerHandle == NULL) {
+ usbi_warn(ctx, "failed to open service control manager: %s", windows_error_str(0));
+ return LIBUSB_ERROR_OTHER;
+ }
- init_polling();
+ serviceHandle = OpenServiceA(managerHandle, "UsbDk", GENERIC_READ);
+ CloseServiceHandle(managerHandle);
- r = windows_common_init(ctx);
- if (r)
- goto init_exit;
- }
- // At this stage, either we went through full init successfully, or didn't need to
- r = LIBUSB_SUCCESS;
-
-init_exit:
- if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
- exit_polling();
- windows_common_exit();
- unload_usbdk_helper_dll();
+ if (serviceHandle == NULL) {
+ if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
+ usbi_warn(ctx, "failed to open UsbDk service: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NOT_FOUND;
}
- if (r != LIBUSB_SUCCESS)
- --concurrent_usage; // Not expected to call libusb_exit if we failed.
+ CloseServiceHandle(serviceHandle);
- return r;
+ return load_usbdk_helper_dll(ctx);
+}
+
+static void usbdk_exit(struct libusb_context *ctx)
+{
+ UNUSED(ctx);
+ unload_usbdk_helper_dll();
}
static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
PUSB_DK_DEVICE_ID id, unsigned long *session_id)
{
- char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID)];
+ char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID) + 1];
- if (sprintf(dev_identity, "%S%S", id->DeviceID, id->InstanceID) == -1) {
+ if (snprintf(dev_identity, sizeof(dev_identity), "%S%S", id->DeviceID, id->InstanceID) == -1) {
usbi_warn(ctx, "cannot form device identity", id->DeviceID);
return LIBUSB_ERROR_NOT_SUPPORTED;
}
@@ -296,11 +270,11 @@ static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info)
dev->port_number = (uint8_t)info->Port;
dev->parent_dev = NULL;
- //Addresses in libusb are 1-based
+ // Addresses in libusb are 1-based
dev->device_address = (uint8_t)(info->Port + 1);
dev->num_configurations = info->DeviceDescriptor.bNumConfigurations;
- dev->device_descriptor = info->DeviceDescriptor;
+ memcpy(&dev->device_descriptor, &info->DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
switch (info->Speed) {
case LowSpeed:
@@ -330,7 +304,7 @@ static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_d
ULONG dev_number;
PUSB_DK_DEVICE_INFO devices;
- if(!usbdk_helper.GetDevicesList(&devices, &dev_number))
+ if (!usbdk_helper.GetDevicesList(&devices, &dev_number))
return LIBUSB_ERROR_OTHER;
for (i = 0; i < dev_number; i++) {
@@ -371,26 +345,16 @@ func_exit:
return r;
}
-static void usbdk_exit(void)
-{
- if (--concurrent_usage < 0) {
- windows_common_exit();
- exit_polling();
- unload_usbdk_helper_dll();
- }
-}
-
-static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian)
+static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer)
{
struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH);
- *host_endian = 0;
return LIBUSB_SUCCESS;
}
-static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
+static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len)
{
struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
PUSB_CONFIGURATION_DESCRIPTOR config_header;
@@ -403,15 +367,31 @@ static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config
size = min(config_header->wTotalLength, len);
memcpy(buffer, config_header, size);
- *host_endian = 0;
-
return (int)size;
}
-static inline int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian)
+static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
+ unsigned char **buffer)
+{
+ struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
+ PUSB_CONFIGURATION_DESCRIPTOR config_header;
+ uint8_t index;
+
+ for (index = 0; index < dev->num_configurations; index++) {
+ config_header = priv->config_descriptors[index];
+ if (config_header->bConfigurationValue == bConfigurationValue) {
+ *buffer = (unsigned char *)priv->config_descriptors[index];
+ return (int)config_header->wTotalLength;
+ }
+ }
+
+ return LIBUSB_ERROR_NOT_FOUND;
+}
+
+static int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len)
{
return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration,
- buffer, len, host_endian);
+ buffer, len);
}
static int usbdk_open(struct libusb_device_handle *dev_handle)
@@ -424,6 +404,8 @@ static int usbdk_open(struct libusb_device_handle *dev_handle)
return LIBUSB_ERROR_OTHER;
}
+ priv->system_handle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
+
return LIBUSB_SUCCESS;
}
@@ -431,10 +413,8 @@ static void usbdk_close(struct libusb_device_handle *dev_handle)
{
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
- if (!usbdk_helper.StopRedirect(priv->redirector_handle)) {
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- usbi_err(ctx, "Redirector shutdown failed");
- }
+ if (!usbdk_helper.StopRedirect(priv->redirector_handle))
+ usbi_err(HANDLE_CTX(dev_handle), "Redirector shutdown failed");
}
static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, int *config)
@@ -460,7 +440,7 @@ static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int if
static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct libusb_context *ctx = HANDLE_CTX(dev_handle);
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
@@ -480,7 +460,7 @@ static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int
static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct libusb_context *ctx = HANDLE_CTX(dev_handle);
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) {
@@ -493,7 +473,7 @@ static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned ch
static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct libusb_context *ctx = HANDLE_CTX(dev_handle);
struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
@@ -504,27 +484,6 @@ static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
return LIBUSB_SUCCESS;
}
-static int usbdk_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface)
-{
- UNUSED(dev_handle);
- UNUSED(iface);
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int usbdk_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
-{
- UNUSED(dev_handle);
- UNUSED(iface);
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int usbdk_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
-{
- UNUSED(dev_handle);
- UNUSED(iface);
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
static void usbdk_destroy_device(struct libusb_device *dev)
{
struct usbdk_device_priv* p = _usbdk_device_priv(dev);
@@ -533,12 +492,14 @@ static void usbdk_destroy_device(struct libusb_device *dev)
usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations);
}
-void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
+static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer)
{
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- usbi_free_fd(&transfer_priv->pollable_fd);
+ usbi_close(transfer_priv->pollable_fd.fd);
+ transfer_priv->pollable_fd = INVALID_WINFD;
+ transfer_priv->system_handle = NULL;
if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
safe_free(transfer_priv->IsochronousPacketsArray);
@@ -551,47 +512,30 @@ static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct winfd wfd;
- ULONG Length;
+ struct libusb_context *ctx = TRANSFER_CTX(transfer);
+ OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
TransferResult transResult;
- HANDLE sysHandle;
-
- sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
-
- wfd = usbi_create_fd(sysHandle, RW_READ, NULL, NULL);
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- if (wfd.fd < 0)
- return LIBUSB_ERROR_NO_MEM;
- transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
+ transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
transfer_priv->request.BufferLength = transfer->length;
transfer_priv->request.TransferType = ControlTransferType;
- transfer_priv->pollable_fd = INVALID_WINFD;
- Length = (ULONG)transfer->length;
- if (IS_XFERIN(transfer))
- transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
+ if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN)
+ transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
else
- transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
+ transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
switch (transResult) {
case TransferSuccess:
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- wfd.overlapped->InternalHigh = (DWORD)Length;
+ windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
break;
case TransferSuccessAsync:
break;
case TransferFailure:
usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0));
- usbi_free_fd(&wfd);
return LIBUSB_ERROR_IO;
}
- // Use priv_transfer to store data needed for async polling
- transfer_priv->pollable_fd = wfd;
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
-
return LIBUSB_SUCCESS;
}
@@ -600,12 +544,11 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct winfd wfd;
+ struct libusb_context *ctx = TRANSFER_CTX(transfer);
+ OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
TransferResult transferRes;
- HANDLE sysHandle;
- transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
+ transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
transfer_priv->request.BufferLength = transfer->length;
transfer_priv->request.EndpointAddress = transfer->endpoint;
@@ -614,42 +557,29 @@ static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
transfer_priv->request.TransferType = BulkTransferType;
break;
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- transfer_priv->request.TransferType = IntertuptTransferType;
+ transfer_priv->request.TransferType = InterruptTransferType;
break;
default:
- usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer. %s", transfer->type, windows_error_str(0));
+ usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer", transfer->type);
return LIBUSB_ERROR_INVALID_PARAM;
}
- transfer_priv->pollable_fd = INVALID_WINFD;
-
- sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
-
- wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- if (wfd.fd < 0)
- return LIBUSB_ERROR_NO_MEM;
-
if (IS_XFERIN(transfer))
- transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
+ transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
else
- transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
+ transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
switch (transferRes) {
case TransferSuccess:
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
+ windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
break;
case TransferSuccessAsync:
break;
case TransferFailure:
usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
- usbi_free_fd(&wfd);
return LIBUSB_ERROR_IO;
}
- transfer_priv->pollable_fd = wfd;
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT);
-
return LIBUSB_SUCCESS;
}
@@ -658,68 +588,81 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct winfd wfd;
+ struct libusb_context *ctx = TRANSFER_CTX(transfer);
+ OVERLAPPED *overlapped = transfer_priv->pollable_fd.overlapped;
TransferResult transferRes;
int i;
- HANDLE sysHandle;
- transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
+ transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
transfer_priv->request.BufferLength = transfer->length;
transfer_priv->request.EndpointAddress = transfer->endpoint;
transfer_priv->request.TransferType = IsochronousTransferType;
transfer_priv->request.IsochronousPacketsArraySize = transfer->num_iso_packets;
transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
- transfer_priv->request.IsochronousPacketsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousPacketsArray;
+ transfer_priv->request.IsochronousPacketsArray = (PVOID64)transfer_priv->IsochronousPacketsArray;
if (!transfer_priv->IsochronousPacketsArray) {
- usbi_err(ctx, "Allocation of IsochronousPacketsArray is failed, %s", windows_error_str(0));
- return LIBUSB_ERROR_IO;
+ usbi_err(ctx, "Allocation of IsochronousPacketsArray failed");
+ return LIBUSB_ERROR_NO_MEM;
}
transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
- transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousResultsArray;
+ transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)transfer_priv->IsochronousResultsArray;
if (!transfer_priv->IsochronousResultsArray) {
- usbi_err(ctx, "Allocation of isochronousResultsArray is failed, %s", windows_error_str(0));
- free(transfer_priv->IsochronousPacketsArray);
- return LIBUSB_ERROR_IO;
+ usbi_err(ctx, "Allocation of isochronousResultsArray failed");
+ return LIBUSB_ERROR_NO_MEM;
}
for (i = 0; i < transfer->num_iso_packets; i++)
transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
- transfer_priv->pollable_fd = INVALID_WINFD;
-
- sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
-
- wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- if (wfd.fd < 0) {
- free(transfer_priv->IsochronousPacketsArray);
- free(transfer_priv->IsochronousResultsArray);
- return LIBUSB_ERROR_NO_MEM;
- }
-
if (IS_XFERIN(transfer))
- transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
+ transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
else
- transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
+ transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
switch (transferRes) {
case TransferSuccess:
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
+ windows_force_sync_completion(overlapped, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
break;
case TransferSuccessAsync:
break;
case TransferFailure:
- usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
- usbi_free_fd(&wfd);
- free(transfer_priv->IsochronousPacketsArray);
- free(transfer_priv->IsochronousResultsArray);
return LIBUSB_ERROR_IO;
}
+ return LIBUSB_SUCCESS;
+}
+
+static int usbdk_do_submit_transfer(struct usbi_transfer *itransfer,
+ short events, int (*transfer_fn)(struct usbi_transfer *))
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = TRANSFER_CTX(transfer);
+ struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
+ struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
+ struct winfd wfd;
+ int r;
+
+ wfd = usbi_create_fd();
+ if (wfd.fd < 0)
+ return LIBUSB_ERROR_NO_MEM;
+
+ r = usbi_add_pollfd(ctx, wfd.fd, events);
+ if (r) {
+ usbi_close(wfd.fd);
+ return r;
+ }
+
+ // Use transfer_priv to store data needed for async polling
transfer_priv->pollable_fd = wfd;
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT);
+ transfer_priv->system_handle = priv->system_handle;
+
+ r = transfer_fn(itransfer);
+ if (r != LIBUSB_SUCCESS) {
+ usbi_remove_pollfd(ctx, wfd.fd);
+ usbdk_clear_transfer_priv(itransfer);
+ return r;
+ }
return LIBUSB_SUCCESS;
}
@@ -727,33 +670,52 @@ static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
static int usbdk_submit_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ int (*transfer_fn)(struct usbi_transfer *);
+ short events;
switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL:
- return usbdk_do_control_transfer(itransfer);
+ events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT;
+ transfer_fn = usbdk_do_control_transfer;
+ break;
case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk
- else
- return usbdk_do_bulk_transfer(itransfer);
+ events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
+ transfer_fn = usbdk_do_bulk_transfer;
+ break;
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- return usbdk_do_iso_transfer(itransfer);
+ events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
+ transfer_fn = usbdk_do_iso_transfer;
+ break;
default:
usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
return LIBUSB_ERROR_INVALID_PARAM;
}
+
+ return usbdk_do_submit_transfer(itransfer, events, transfer_fn);
}
static int usbdk_abort_transfers(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct libusb_context *ctx = TRANSFER_CTX(transfer);
struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
+ struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
+ struct winfd *pollable_fd = &transfer_priv->pollable_fd;
- if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) {
- usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
+ if (pCancelIoEx != NULL) {
+ // Use CancelIoEx if available to cancel just a single transfer
+ if (!pCancelIoEx(priv->system_handle, pollable_fd->overlapped)) {
+ usbi_err(ctx, "CancelIoEx failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+ } else {
+ if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) {
+ usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
}
return LIBUSB_SUCCESS;
@@ -778,16 +740,16 @@ static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
}
}
-int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
+static int usbdk_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
{
itransfer->transferred += io_size;
return LIBUSB_TRANSFER_COMPLETED;
}
-struct winfd *windows_get_fd(struct usbi_transfer *transfer)
+static int usbdk_get_transfer_fd(struct usbi_transfer *itransfer)
{
- struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
- return &transfer_priv->pollable_fd;
+ struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
+ return transfer_priv->pollable_fd.fd;
}
static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
@@ -796,30 +758,28 @@ static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
return NO_ERROR;
switch (UsbdStatus) {
- case USBD_STATUS_STALL_PID:
- case USBD_STATUS_ENDPOINT_HALTED:
- case USBD_STATUS_BAD_START_FRAME:
- return ERROR_GEN_FAILURE;
case USBD_STATUS_TIMEOUT:
return ERROR_SEM_TIMEOUT;
case USBD_STATUS_CANCELED:
return ERROR_OPERATION_ABORTED;
default:
- return ERROR_FUNCTION_FAILED;
+ return ERROR_GEN_FAILURE;
}
}
-void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size)
+static void usbdk_get_overlapped_result(struct usbi_transfer *itransfer, DWORD *io_result, DWORD *io_size)
{
+ struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
+ struct winfd *pollable_fd = &transfer_priv->pollable_fd;
+
if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first
- || GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) { // Regular async overlapped
- struct libusb_transfer *ltransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer);
- struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
+ || GetOverlappedResult(transfer_priv->system_handle, pollable_fd->overlapped, io_size, FALSE)) { // Regular async overlapped
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- if (ltransfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
- int i;
+ if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
+ ULONG64 i;
for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
- struct libusb_iso_packet_descriptor *lib_desc = &ltransfer->iso_packet_desc[i];
+ struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
case STATUS_SUCCESS:
@@ -836,70 +796,35 @@ void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd
}
}
- *io_size = (DWORD) transfer_priv->request.Result.GenResult.BytesTransferred;
- *io_result = usbdk_translate_usbd_status((USBD_STATUS) transfer_priv->request.Result.GenResult.UsbdStatus);
- }
- else {
+ *io_size = (DWORD)transfer_priv->request.Result.GenResult.BytesTransferred;
+ *io_result = usbdk_translate_usbd_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus);
+ } else {
*io_result = GetLastError();
}
}
-static int usbdk_clock_gettime(int clk_id, struct timespec *tp)
-{
- return windows_clock_gettime(clk_id, tp);
-}
-
-const struct usbi_os_backend usbdk_backend = {
- "Windows",
- USBI_CAP_HAS_HID_ACCESS,
+const struct windows_backend usbdk_backend = {
usbdk_init,
usbdk_exit,
-
usbdk_get_device_list,
- NULL,
usbdk_open,
usbdk_close,
-
usbdk_get_device_descriptor,
usbdk_get_active_config_descriptor,
usbdk_get_config_descriptor,
- NULL,
-
+ usbdk_get_config_descriptor_by_value,
usbdk_get_configuration,
usbdk_set_configuration,
usbdk_claim_interface,
usbdk_release_interface,
-
usbdk_set_interface_altsetting,
usbdk_clear_halt,
usbdk_reset_device,
-
- NULL,
- NULL,
-
- NULL, // dev_mem_alloc()
- NULL, // dev_mem_free()
-
- usbdk_kernel_driver_active,
- usbdk_detach_kernel_driver,
- usbdk_attach_kernel_driver,
-
usbdk_destroy_device,
-
usbdk_submit_transfer,
usbdk_cancel_transfer,
- windows_clear_transfer_priv,
-
- windows_handle_events,
- NULL,
-
- usbdk_clock_gettime,
-#if defined(USBI_TIMERFD_AVAILABLE)
- NULL,
-#endif
- sizeof(struct usbdk_device_priv),
- 0,
- sizeof(struct usbdk_transfer_priv),
+ usbdk_clear_transfer_priv,
+ usbdk_copy_transfer_data,
+ usbdk_get_transfer_fd,
+ usbdk_get_overlapped_result,
};
-
-#endif /* USE_USBDK */
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_usbdk.h
index 04a9787f2..77660ae97 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_usbdk.h
@@ -23,56 +23,13 @@
#pragma once
-typedef struct tag_USB_DK_DEVICE_ID {
- WCHAR DeviceID[MAX_DEVICE_ID_LEN];
- WCHAR InstanceID[MAX_DEVICE_ID_LEN];
-} USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID;
+#include "windows_nt_common.h"
-static inline void UsbDkFillIDStruct(USB_DK_DEVICE_ID *ID, PCWCHAR DeviceID, PCWCHAR InstanceID)
-{
- wcsncpy_s(ID->DeviceID, DeviceID, MAX_DEVICE_ID_LEN);
- wcsncpy_s(ID->InstanceID, InstanceID, MAX_DEVICE_ID_LEN);
-}
-
-typedef struct tag_USB_DK_DEVICE_INFO {
- USB_DK_DEVICE_ID ID;
- ULONG64 FilterID;
- ULONG64 Port;
- ULONG64 Speed;
- USB_DEVICE_DESCRIPTOR DeviceDescriptor;
-} USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO;
-
-typedef struct tag_USB_DK_CONFIG_DESCRIPTOR_REQUEST {
+typedef struct USB_DK_CONFIG_DESCRIPTOR_REQUEST {
USB_DK_DEVICE_ID ID;
ULONG64 Index;
} USB_DK_CONFIG_DESCRIPTOR_REQUEST, *PUSB_DK_CONFIG_DESCRIPTOR_REQUEST;
-typedef struct tag_USB_DK_ISO_TRANSFER_RESULT {
- ULONG64 ActualLength;
- ULONG64 TransferResult;
-} USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT;
-
-typedef struct tag_USB_DK_GEN_TRANSFER_RESULT {
- ULONG64 BytesTransferred;
- ULONG64 UsbdStatus; // USBD_STATUS code
-} USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT;
-
-typedef struct tag_USB_DK_TRANSFER_RESULT {
- USB_DK_GEN_TRANSFER_RESULT GenResult;
- PVOID64 IsochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT
-} USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT;
-
-typedef struct tag_USB_DK_TRANSFER_REQUEST {
- ULONG64 EndpointAddress;
- PVOID64 Buffer;
- ULONG64 BufferLength;
- ULONG64 TransferType;
- ULONG64 IsochronousPacketsArraySize;
- PVOID64 IsochronousPacketsArray;
-
- USB_DK_TRANSFER_RESULT Result;
-} USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST;
-
typedef enum {
TransferFailure = 0,
TransferSuccess,
@@ -90,7 +47,7 @@ typedef enum {
typedef enum {
ControlTransferType,
BulkTransferType,
- IntertuptTransferType,
+ InterruptTransferType,
IsochronousTransferType
} USB_DK_TRANSFER_TYPE;
diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.c b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.c
new file mode 100644
index 000000000..ce1b55cd6
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.c
@@ -0,0 +1,3009 @@
+/*
+ * windows backend for libusb 1.0
+ * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
+ * Copyright © 2016-2018 Chris Dickens <christopher.a.dickens@gmail.com>
+ * With contributions from Michael Plante, Orin Eman et al.
+ * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
+ * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software
+ * Hash table functions adapted from glibc, by Ulrich Drepper et al.
+ * Major code testing contribution by Xiaofan Chen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <windows.h>
+#include <setupapi.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <process.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <objbase.h>
+#include <winioctl.h>
+
+#include "libusbi.h"
+#include "windows_common.h"
+#include "windows_nt_common.h"
+#include "windows_winusb.h"
+
+// Unfuckup the 'inferface' keyword
+#undef interface
+
+#define HANDLE_VALID(h) (((h) != NULL) && ((h) != INVALID_HANDLE_VALUE))
+
+// The 2 macros below are used in conjunction with safe loops.
+#define LOOP_CHECK(fcall) \
+ { \
+ r = fcall; \
+ if (r != LIBUSB_SUCCESS) \
+ continue; \
+ }
+#define LOOP_BREAK(err) \
+ { \
+ r = err; \
+ continue; \
+ }
+
+// WinUSB-like API prototypes
+static int winusbx_init(struct libusb_context *ctx);
+static void winusbx_exit(void);
+static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle);
+static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle);
+static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface);
+static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
+static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
+static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
+static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting);
+static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer);
+static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
+static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
+static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer);
+static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer);
+static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
+static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
+// Composite API prototypes
+static int composite_open(int sub_api, struct libusb_device_handle *dev_handle);
+static void composite_close(int sub_api, struct libusb_device_handle *dev_handle);
+static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
+static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting);
+static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
+static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
+static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
+static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer);
+static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
+static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer);
+static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer);
+static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
+static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
+
+static usbi_mutex_t autoclaim_lock;
+
+// API globals
+static HMODULE WinUSBX_handle = NULL;
+static struct winusb_interface WinUSBX[SUB_API_MAX];
+#define CHECK_WINUSBX_AVAILABLE(sub_api) \
+ do { \
+ if (sub_api == SUB_API_NOTSET) \
+ sub_api = priv->sub_api; \
+ if (!WinUSBX[sub_api].initialized) \
+ return LIBUSB_ERROR_ACCESS; \
+ } while (0)
+
+static bool api_hid_available = false;
+#define CHECK_HID_AVAILABLE \
+ do { \
+ if (!api_hid_available) \
+ return LIBUSB_ERROR_ACCESS; \
+ } while (0)
+
+#if defined(ENABLE_LOGGING)
+static const char *guid_to_string(const GUID *guid)
+{
+ static char guid_string[MAX_GUID_STRING_LENGTH];
+
+ if (guid == NULL)
+ return "";
+
+ sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+ (unsigned int)guid->Data1, guid->Data2, guid->Data3,
+ guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
+ guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
+
+ return guid_string;
+}
+#endif
+
+/*
+ * Sanitize Microsoft's paths: convert to uppercase, add prefix and fix backslashes.
+ * Return an allocated sanitized string or NULL on error.
+ */
+static char *sanitize_path(const char *path)
+{
+ const char root_prefix[] = {'\\', '\\', '.', '\\'};
+ size_t j, size;
+ char *ret_path;
+ size_t add_root = 0;
+
+ if (path == NULL)
+ return NULL;
+
+ size = strlen(path) + 1;
+
+ // Microsoft indiscriminately uses '\\?\', '\\.\', '##?#" or "##.#" for root prefixes.
+ if (!((size > 3) && (((path[0] == '\\') && (path[1] == '\\') && (path[3] == '\\'))
+ || ((path[0] == '#') && (path[1] == '#') && (path[3] == '#'))))) {
+ add_root = sizeof(root_prefix);
+ size += add_root;
+ }
+
+ ret_path = malloc(size);
+ if (ret_path == NULL)
+ return NULL;
+
+ strcpy(&ret_path[add_root], path);
+
+ // Ensure consistency with root prefix
+ memcpy(ret_path, root_prefix, sizeof(root_prefix));
+
+ // Same goes for '\' and '#' after the root prefix. Ensure '#' is used
+ for (j = sizeof(root_prefix); j < size; j++) {
+ ret_path[j] = (char)toupper((int)ret_path[j]); // Fix case too
+ if (ret_path[j] == '\\')
+ ret_path[j] = '#';
+ }
+
+ return ret_path;
+}
+
+/*
+ * Cfgmgr32, AdvAPI32, OLE32 and SetupAPI DLL functions
+ */
+static BOOL init_dlls(void)
+{
+ DLL_GET_HANDLE(Cfgmgr32);
+ DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, TRUE);
+ DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, TRUE);
+
+ // Prefixed to avoid conflict with header files
+ DLL_GET_HANDLE(AdvAPI32);
+ DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, TRUE);
+ DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, TRUE);
+
+ DLL_GET_HANDLE(OLE32);
+ DLL_LOAD_FUNC_PREFIXED(OLE32, p, IIDFromString, TRUE);
+
+ DLL_GET_HANDLE(SetupAPI);
+ DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, TRUE);
+ DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, TRUE);
+ DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, TRUE);
+ DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInstanceIdA, TRUE);
+ DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, TRUE);
+ DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, TRUE);
+ DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, TRUE);
+ DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, TRUE);
+ DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, TRUE);
+
+ return TRUE;
+}
+
+static void exit_dlls(void)
+{
+ DLL_FREE_HANDLE(Cfgmgr32);
+ DLL_FREE_HANDLE(AdvAPI32);
+ DLL_FREE_HANDLE(OLE32);
+ DLL_FREE_HANDLE(SetupAPI);
+}
+
+/*
+ * enumerate interfaces for the whole USB class
+ *
+ * Parameters:
+ * dev_info: a pointer to a dev_info list
+ * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed)
+ * enumerator: the generic USB class for which to retrieve interface details
+ * index: zero based index of the interface in the device info list
+ *
+ * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA
+ * structure returned and call this function repeatedly using the same guid (with an
+ * incremented index starting at zero) until all interfaces have been returned.
+ */
+static bool get_devinfo_data(struct libusb_context *ctx,
+ HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const char *enumerator, unsigned _index)
+{
+ if (_index == 0) {
+ *dev_info = pSetupDiGetClassDevsA(NULL, enumerator, NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES);
+ if (*dev_info == INVALID_HANDLE_VALUE) {
+ usbi_err(ctx, "could not obtain device info set for PnP enumerator '%s': %s",
+ enumerator, windows_error_str(0));
+ return false;
+ }
+ }
+
+ dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
+ if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) {
+ if (GetLastError() != ERROR_NO_MORE_ITEMS)
+ usbi_err(ctx, "could not obtain device info data for PnP enumerator '%s' index %u: %s",
+ enumerator, _index, windows_error_str(0));
+
+ pSetupDiDestroyDeviceInfoList(*dev_info);
+ *dev_info = INVALID_HANDLE_VALUE;
+ return false;
+ }
+ return true;
+}
+
+/*
+ * enumerate interfaces for a specific GUID
+ *
+ * Parameters:
+ * dev_info: a pointer to a dev_info list
+ * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed)
+ * guid: the GUID for which to retrieve interface details
+ * index: zero based index of the interface in the device info list
+ *
+ * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA
+ * structure returned and call this function repeatedly using the same guid (with an
+ * incremented index starting at zero) until all interfaces have been returned.
+ */
+static int get_interface_details(struct libusb_context *ctx, HDEVINFO dev_info,
+ PSP_DEVINFO_DATA dev_info_data, LPCGUID guid, DWORD *_index, char **dev_interface_path)
+{
+ SP_DEVICE_INTERFACE_DATA dev_interface_data;
+ PSP_DEVICE_INTERFACE_DETAIL_DATA_A dev_interface_details;
+ DWORD size;
+
+ dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
+ dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+ for (;;) {
+ if (!pSetupDiEnumDeviceInfo(dev_info, *_index, dev_info_data)) {
+ if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+ usbi_err(ctx, "Could not obtain device info data for %s index %u: %s",
+ guid_to_string(guid), *_index, windows_error_str(0));
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ // No more devices
+ return LIBUSB_SUCCESS;
+ }
+
+ // Always advance the index for the next iteration
+ (*_index)++;
+
+ if (pSetupDiEnumDeviceInterfaces(dev_info, dev_info_data, guid, 0, &dev_interface_data))
+ break;
+
+ if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+ usbi_err(ctx, "Could not obtain interface data for %s devInst %X: %s",
+ guid_to_string(guid), dev_info_data->DevInst, windows_error_str(0));
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ // Device does not have an interface matching this GUID, skip
+ }
+
+ // Read interface data (dummy + actual) to access the device path
+ if (!pSetupDiGetDeviceInterfaceDetailA(dev_info, &dev_interface_data, NULL, 0, &size, NULL)) {
+ // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ usbi_err(ctx, "could not access interface data (dummy) for %s devInst %X: %s",
+ guid_to_string(guid), dev_info_data->DevInst, windows_error_str(0));
+ return LIBUSB_ERROR_OTHER;
+ }
+ } else {
+ usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong");
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ dev_interface_details = malloc(size);
+ if (dev_interface_details == NULL) {
+ usbi_err(ctx, "could not allocate interface data for %s devInst %X",
+ guid_to_string(guid), dev_info_data->DevInst);
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
+ if (!pSetupDiGetDeviceInterfaceDetailA(dev_info, &dev_interface_data,
+ dev_interface_details, size, NULL, NULL)) {
+ usbi_err(ctx, "could not access interface data (actual) for %s devInst %X: %s",
+ guid_to_string(guid), dev_info_data->DevInst, windows_error_str(0));
+ free(dev_interface_details);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ *dev_interface_path = sanitize_path(dev_interface_details->DevicePath);
+ free(dev_interface_details);
+
+ if (*dev_interface_path == NULL) {
+ usbi_err(ctx, "could not allocate interface path for %s devInst %X",
+ guid_to_string(guid), dev_info_data->DevInst);
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+/* For libusb0 filter */
+static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details_filter(struct libusb_context *ctx,
+ HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID *guid, unsigned _index, char *filter_path)
+{
+ SP_DEVICE_INTERFACE_DATA dev_interface_data;
+ SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details;
+ DWORD size;
+
+ if (_index == 0)
+ *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
+
+ if (dev_info_data != NULL) {
+ dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
+ if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) {
+ if (GetLastError() != ERROR_NO_MORE_ITEMS)
+ usbi_err(ctx, "Could not obtain device info data for index %u: %s",
+ _index, windows_error_str(0));
+
+ pSetupDiDestroyDeviceInfoList(*dev_info);
+ *dev_info = INVALID_HANDLE_VALUE;
+ return NULL;
+ }
+ }
+
+ dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+ if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, guid, _index, &dev_interface_data)) {
+ if (GetLastError() != ERROR_NO_MORE_ITEMS)
+ usbi_err(ctx, "Could not obtain interface data for index %u: %s",
+ _index, windows_error_str(0));
+
+ pSetupDiDestroyDeviceInfoList(*dev_info);
+ *dev_info = INVALID_HANDLE_VALUE;
+ return NULL;
+ }
+
+ // Read interface data (dummy + actual) to access the device path
+ if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) {
+ // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ usbi_err(ctx, "could not access interface data (dummy) for index %u: %s",
+ _index, windows_error_str(0));
+ goto err_exit;
+ }
+ } else {
+ usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong.");
+ goto err_exit;
+ }
+
+ dev_interface_details = calloc(1, size);
+ if (dev_interface_details == NULL) {
+ usbi_err(ctx, "could not allocate interface data for index %u.", _index);
+ goto err_exit;
+ }
+
+ dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
+ if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, dev_interface_details, size, &size, NULL))
+ usbi_err(ctx, "could not access interface data (actual) for index %u: %s",
+ _index, windows_error_str(0));
+
+ // [trobinso] lookup the libusb0 symbolic index.
+ if (dev_interface_details) {
+ HKEY hkey_device_interface = pSetupDiOpenDeviceInterfaceRegKey(*dev_info, &dev_interface_data, 0, KEY_READ);
+ if (hkey_device_interface != INVALID_HANDLE_VALUE) {
+ DWORD libusb0_symboliclink_index = 0;
+ DWORD value_length = sizeof(DWORD);
+ DWORD value_type = 0;
+ LONG status;
+
+ status = pRegQueryValueExW(hkey_device_interface, L"LUsb0", NULL, &value_type,
+ (LPBYTE)&libusb0_symboliclink_index, &value_length);
+ if (status == ERROR_SUCCESS) {
+ if (libusb0_symboliclink_index < 256) {
+ // libusb0.sys is connected to this device instance.
+ // If the the device interface guid is {F9F3FF14-AE21-48A0-8A25-8011A7A931D9} then it's a filter.
+ sprintf(filter_path, "\\\\.\\libusb0-%04u", (unsigned int)libusb0_symboliclink_index);
+ usbi_dbg("assigned libusb0 symbolic link %s", filter_path);
+ } else {
+ // libusb0.sys was connected to this device instance at one time; but not anymore.
+ }
+ }
+ pRegCloseKey(hkey_device_interface);
+ }
+ }
+
+ return dev_interface_details;
+
+err_exit:
+ pSetupDiDestroyDeviceInfoList(*dev_info);
+ *dev_info = INVALID_HANDLE_VALUE;
+ return NULL;
+}
+
+/*
+ * Returns the first known ancestor of a device
+ */
+static struct libusb_device *get_ancestor(struct libusb_context *ctx,
+ DEVINST devinst, PDEVINST _parent_devinst)
+{
+ struct libusb_device *dev = NULL;
+ DEVINST parent_devinst;
+
+ while (dev == NULL) {
+ if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS)
+ break;
+ devinst = parent_devinst;
+ dev = usbi_get_device_by_session_id(ctx, (unsigned long)devinst);
+ }
+
+ if ((dev != NULL) && (_parent_devinst != NULL))
+ *_parent_devinst = devinst;
+
+ return dev;
+}
+
+/*
+ * Determine which interface the given endpoint address belongs to
+ */
+static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, uint8_t ep)
+{
+ const struct libusb_interface *intf;
+ const struct libusb_interface_descriptor *intf_desc;
+ int i, j, k;
+
+ for (i = 0; i < conf_desc->bNumInterfaces; i++) {
+ intf = &conf_desc->interface[i];
+ for (j = 0; j < intf->num_altsetting; j++) {
+ intf_desc = &intf->altsetting[j];
+ for (k = 0; k < intf_desc->bNumEndpoints; k++) {
+ if (intf_desc->endpoint[k].bEndpointAddress == ep) {
+ usbi_dbg("found endpoint %02X on interface %d", intf_desc->bInterfaceNumber, i);
+ return intf_desc->bInterfaceNumber;
+ }
+ }
+ }
+ }
+
+ usbi_dbg("endpoint %02X not found on any interface", ep);
+ return LIBUSB_ERROR_NOT_FOUND;
+}
+
+/*
+ * Populate the endpoints addresses of the device_priv interface helper structs
+ */
+static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int iface, int altsetting)
+{
+ int i, r;
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ struct libusb_config_descriptor *conf_desc;
+ const struct libusb_interface_descriptor *if_desc;
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+
+ r = libusb_get_active_config_descriptor(dev_handle->dev, &conf_desc);
+ if (r != LIBUSB_SUCCESS) {
+ usbi_warn(ctx, "could not read config descriptor: error %d", r);
+ return r;
+ }
+
+ if_desc = &conf_desc->interface[iface].altsetting[altsetting];
+ safe_free(priv->usb_interface[iface].endpoint);
+
+ if (if_desc->bNumEndpoints == 0) {
+ usbi_dbg("no endpoints found for interface %d", iface);
+ libusb_free_config_descriptor(conf_desc);
+ return LIBUSB_SUCCESS;
+ }
+
+ priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints);
+ if (priv->usb_interface[iface].endpoint == NULL) {
+ libusb_free_config_descriptor(conf_desc);
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints;
+ for (i = 0; i < if_desc->bNumEndpoints; i++) {
+ priv->usb_interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress;
+ usbi_dbg("(re)assigned endpoint %02X to interface %d", priv->usb_interface[iface].endpoint[i], iface);
+ }
+ libusb_free_config_descriptor(conf_desc);
+
+ // Extra init may be required to configure endpoints
+ if (priv->apib->configure_endpoints)
+ r = priv->apib->configure_endpoints(SUB_API_NOTSET, dev_handle, iface);
+
+ return r;
+}
+
+// Lookup for a match in the list of API driver names
+// return -1 if not found, driver match number otherwise
+static int get_sub_api(char *driver, int api)
+{
+ int i;
+ const char sep_str[2] = {LIST_SEPARATOR, 0};
+ char *tok, *tmp_str;
+ size_t len = strlen(driver);
+
+ if (len == 0)
+ return SUB_API_NOTSET;
+
+ tmp_str = _strdup(driver);
+ if (tmp_str == NULL)
+ return SUB_API_NOTSET;
+
+ tok = strtok(tmp_str, sep_str);
+ while (tok != NULL) {
+ for (i = 0; i < usb_api_backend[api].nb_driver_names; i++) {
+ if (_stricmp(tok, usb_api_backend[api].driver_name_list[i]) == 0) {
+ free(tmp_str);
+ return i;
+ }
+ }
+ tok = strtok(NULL, sep_str);
+ }
+
+ free(tmp_str);
+ return SUB_API_NOTSET;
+}
+
+/*
+ * auto-claiming and auto-release helper functions
+ */
+static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type)
+{
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(
+ transfer->dev_handle);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ int current_interface = *interface_number;
+ int r = LIBUSB_SUCCESS;
+
+ switch (api_type) {
+ case USB_API_WINUSBX:
+ case USB_API_HID:
+ break;
+ default:
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ usbi_mutex_lock(&autoclaim_lock);
+ if (current_interface < 0) { // No serviceable interface was found
+ for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) {
+ // Must claim an interface of the same API type
+ if ((priv->usb_interface[current_interface].apib->id == api_type)
+ && (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS)) {
+ usbi_dbg("auto-claimed interface %d for control request", current_interface);
+ if (handle_priv->autoclaim_count[current_interface] != 0)
+ usbi_warn(ctx, "program assertion failed - autoclaim_count was nonzero");
+ handle_priv->autoclaim_count[current_interface]++;
+ break;
+ }
+ }
+ if (current_interface == USB_MAXINTERFACES) {
+ usbi_err(ctx, "could not auto-claim any interface");
+ r = LIBUSB_ERROR_NOT_FOUND;
+ }
+ } else {
+ // If we have a valid interface that was autoclaimed, we must increment
+ // its autoclaim count so that we can prevent an early release.
+ if (handle_priv->autoclaim_count[current_interface] != 0)
+ handle_priv->autoclaim_count[current_interface]++;
+ }
+ usbi_mutex_unlock(&autoclaim_lock);
+
+ *interface_number = current_interface;
+ return r;
+}
+
+static void auto_release(struct usbi_transfer *itransfer)
+{
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ libusb_device_handle *dev_handle = transfer->dev_handle;
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
+ int r;
+
+ usbi_mutex_lock(&autoclaim_lock);
+ if (handle_priv->autoclaim_count[transfer_priv->interface_number] > 0) {
+ handle_priv->autoclaim_count[transfer_priv->interface_number]--;
+ if (handle_priv->autoclaim_count[transfer_priv->interface_number] == 0) {
+ r = libusb_release_interface(dev_handle, transfer_priv->interface_number);
+ if (r == LIBUSB_SUCCESS)
+ usbi_dbg("auto-released interface %d", transfer_priv->interface_number);
+ else
+ usbi_dbg("failed to auto-release interface %d (%s)",
+ transfer_priv->interface_number, libusb_error_name((enum libusb_error)r));
+ }
+ }
+ usbi_mutex_unlock(&autoclaim_lock);
+}
+
+/*
+ * init: libusb backend init function
+ */
+static int winusb_init(struct libusb_context *ctx)
+{
+ int i;
+
+ // We need a lock for proper auto-release
+ usbi_mutex_init(&autoclaim_lock);
+
+ // Load DLL imports
+ if (!init_dlls()) {
+ usbi_err(ctx, "could not resolve DLL functions");
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ // Initialize the low level APIs (we don't care about errors at this stage)
+ for (i = 0; i < USB_API_MAX; i++) {
+ if (usb_api_backend[i].init && usb_api_backend[i].init(ctx))
+ usbi_warn(ctx, "error initializing %s backend",
+ usb_api_backend[i].designation);
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+/*
+* exit: libusb backend deinitialization function
+*/
+static void winusb_exit(struct libusb_context *ctx)
+{
+ int i;
+
+ for (i = 0; i < USB_API_MAX; i++) {
+ if (usb_api_backend[i].exit)
+ usb_api_backend[i].exit();
+ }
+
+ exit_dlls();
+ usbi_mutex_destroy(&autoclaim_lock);
+}
+
+/*
+ * fetch and cache all the config descriptors through I/O
+ */
+static void cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev);
+ struct winusb_device_priv *priv = _device_priv(dev);
+ DWORD size, ret_size;
+ uint8_t i;
+
+ USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request
+ PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request
+ PUSB_CONFIGURATION_DESCRIPTOR cd_data;
+
+ if (dev->num_configurations == 0)
+ return;
+
+ priv->config_descriptor = calloc(dev->num_configurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
+ if (priv->config_descriptor == NULL) {
+ usbi_err(ctx, "could not allocate configuration descriptor array for '%s'", priv->dev_id);
+ return;
+ }
+
+ for (i = 0; i <= dev->num_configurations; i++) {
+ safe_free(cd_buf_actual);
+
+ if (i == dev->num_configurations)
+ break;
+
+ size = sizeof(cd_buf_short);
+ memset(&cd_buf_short, 0, size);
+
+ cd_buf_short.req.ConnectionIndex = (ULONG)dev->port_number;
+ cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
+ cd_buf_short.req.SetupPacket.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR;
+ cd_buf_short.req.SetupPacket.wValue = (LIBUSB_DT_CONFIG << 8) | i;
+ cd_buf_short.req.SetupPacket.wIndex = 0;
+ cd_buf_short.req.SetupPacket.wLength = (USHORT)sizeof(USB_CONFIGURATION_DESCRIPTOR);
+
+ // Dummy call to get the required data size. Initial failures are reported as info rather
+ // than error as they can occur for non-penalizing situations, such as with some hubs.
+ // coverity[tainted_data_argument]
+ if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &cd_buf_short, size,
+ &cd_buf_short, size, &ret_size, NULL)) {
+ usbi_info(ctx, "could not access configuration descriptor %u (dummy) for '%s': %s", i, priv->dev_id, windows_error_str(0));
+ continue;
+ }
+
+ if ((ret_size != size) || (cd_buf_short.desc.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))) {
+ usbi_info(ctx, "unexpected configuration descriptor %u size (dummy) for '%s'", i, priv->dev_id);
+ continue;
+ }
+
+ size = sizeof(USB_DESCRIPTOR_REQUEST) + cd_buf_short.desc.wTotalLength;
+ cd_buf_actual = malloc(size);
+ if (cd_buf_actual == NULL) {
+ usbi_err(ctx, "could not allocate configuration descriptor %u buffer for '%s'", i, priv->dev_id);
+ continue;
+ }
+
+ // Actual call
+ cd_buf_actual->ConnectionIndex = (ULONG)dev->port_number;
+ cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
+ cd_buf_actual->SetupPacket.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR;
+ cd_buf_actual->SetupPacket.wValue = (LIBUSB_DT_CONFIG << 8) | i;
+ cd_buf_actual->SetupPacket.wIndex = 0;
+ cd_buf_actual->SetupPacket.wLength = cd_buf_short.desc.wTotalLength;
+
+ if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, cd_buf_actual, size,
+ cd_buf_actual, size, &ret_size, NULL)) {
+ usbi_err(ctx, "could not access configuration descriptor %u (actual) for '%s': %s", i, priv->dev_id, windows_error_str(0));
+ continue;
+ }
+
+ cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR *)cd_buf_actual + sizeof(USB_DESCRIPTOR_REQUEST));
+
+ if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.desc.wTotalLength)) {
+ usbi_err(ctx, "unexpected configuration descriptor %u size (actual) for '%s'", i, priv->dev_id);
+ continue;
+ }
+
+ if (cd_data->bDescriptorType != LIBUSB_DT_CONFIG) {
+ usbi_err(ctx, "descriptor %u not a configuration descriptor for '%s'", i, priv->dev_id);
+ continue;
+ }
+
+ usbi_dbg("cached config descriptor %u (bConfigurationValue=%u, %u bytes)",
+ i, cd_data->bConfigurationValue, cd_data->wTotalLength);
+
+ // Cache the descriptor
+ priv->config_descriptor[i] = malloc(cd_data->wTotalLength);
+ if (priv->config_descriptor[i] != NULL) {
+ memcpy(priv->config_descriptor[i], cd_data, cd_data->wTotalLength);
+ } else {
+ usbi_err(ctx, "could not allocate configuration descriptor %u buffer for '%s'", i, priv->dev_id);
+ }
+ }
+}
+
+/*
+ * Populate a libusb device structure
+ */
+static int init_device(struct libusb_device *dev, struct libusb_device *parent_dev,
+ uint8_t port_number, DEVINST devinst)
+{
+ struct libusb_context *ctx;
+ struct libusb_device *tmp_dev;
+ struct winusb_device_priv *priv, *parent_priv;
+ USB_NODE_CONNECTION_INFORMATION_EX conn_info;
+ USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2;
+ HANDLE hub_handle;
+ DWORD size;
+ uint8_t bus_number, depth;
+ int r;
+
+ priv = _device_priv(dev);
+
+ // If the device is already initialized, we can stop here
+ if (priv->initialized)
+ return LIBUSB_SUCCESS;
+
+ if (parent_dev != NULL) { // Not a HCD root hub
+ ctx = DEVICE_CTX(dev);
+ parent_priv = _device_priv(parent_dev);
+ if (parent_priv->apib->id != USB_API_HUB) {
+ usbi_warn(ctx, "parent for device '%s' is not a hub", priv->dev_id);
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ // Calculate depth and fetch bus number
+ bus_number = parent_dev->bus_number;
+ if (bus_number == 0) {
+ tmp_dev = get_ancestor(ctx, devinst, &devinst);
+ if (tmp_dev != parent_dev) {
+ usbi_err(ctx, "program assertion failed - first ancestor is not parent");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+ libusb_unref_device(tmp_dev);
+
+ for (depth = 1; bus_number == 0; depth++) {
+ tmp_dev = get_ancestor(ctx, devinst, &devinst);
+ if (tmp_dev->bus_number != 0) {
+ bus_number = tmp_dev->bus_number;
+ depth += _device_priv(tmp_dev)->depth;
+ }
+ libusb_unref_device(tmp_dev);
+ }
+ } else {
+ depth = parent_priv->depth + 1;
+ }
+
+ if (bus_number == 0) {
+ usbi_err(ctx, "program assertion failed - bus number not found for '%s'", priv->dev_id);
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ dev->bus_number = bus_number;
+ dev->port_number = port_number;
+ dev->parent_dev = parent_dev;
+ priv->depth = depth;
+
+ hub_handle = CreateFileA(parent_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ 0, NULL);
+ if (hub_handle == INVALID_HANDLE_VALUE) {
+ usbi_warn(ctx, "could not open hub %s: %s", parent_priv->path, windows_error_str(0));
+ return LIBUSB_ERROR_ACCESS;
+ }
+
+ memset(&conn_info, 0, sizeof(conn_info));
+ conn_info.ConnectionIndex = (ULONG)port_number;
+ // coverity[tainted_data_argument]
+ if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, sizeof(conn_info),
+ &conn_info, sizeof(conn_info), &size, NULL)) {
+ usbi_warn(ctx, "could not get node connection information for device '%s': %s",
+ priv->dev_id, windows_error_str(0));
+ CloseHandle(hub_handle);
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ if (conn_info.ConnectionStatus == NoDeviceConnected) {
+ usbi_err(ctx, "device '%s' is no longer connected!", priv->dev_id);
+ CloseHandle(hub_handle);
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR));
+ dev->num_configurations = priv->dev_descriptor.bNumConfigurations;
+ priv->active_config = conn_info.CurrentConfigurationValue;
+ usbi_dbg("found %u configurations (active conf: %u)", dev->num_configurations, priv->active_config);
+
+ // Cache as many config descriptors as we can
+ cache_config_descriptors(dev, hub_handle);
+
+ // In their great wisdom, Microsoft decided to BREAK the USB speed report between Windows 7 and Windows 8
+ if (windows_version >= WINDOWS_8) {
+ conn_info_v2.ConnectionIndex = (ULONG)port_number;
+ conn_info_v2.Length = sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2);
+ conn_info_v2.SupportedUsbProtocols.Usb300 = 1;
+ if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2,
+ &conn_info_v2, sizeof(conn_info_v2), &conn_info_v2, sizeof(conn_info_v2), &size, NULL)) {
+ usbi_warn(ctx, "could not get node connection information (V2) for device '%s': %s",
+ priv->dev_id, windows_error_str(0));
+ } else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedOrHigher) {
+ conn_info.Speed = 3;
+ }
+ }
+
+ CloseHandle(hub_handle);
+
+ if (conn_info.DeviceAddress > UINT8_MAX)
+ usbi_err(ctx, "program assertion failed - device address overflow");
+
+ dev->device_address = (uint8_t)conn_info.DeviceAddress;
+
+ switch (conn_info.Speed) {
+ case 0: dev->speed = LIBUSB_SPEED_LOW; break;
+ case 1: dev->speed = LIBUSB_SPEED_FULL; break;
+ case 2: dev->speed = LIBUSB_SPEED_HIGH; break;
+ case 3: dev->speed = LIBUSB_SPEED_SUPER; break;
+ default:
+ usbi_warn(ctx, "unknown device speed %u", conn_info.Speed);
+ break;
+ }
+ }
+
+ r = usbi_sanitize_device(dev);
+ if (r)
+ return r;
+
+ priv->initialized = true;
+
+ usbi_dbg("(bus: %u, addr: %u, depth: %u, port: %u): '%s'",
+ dev->bus_number, dev->device_address, priv->depth, dev->port_number, priv->dev_id);
+
+ return LIBUSB_SUCCESS;
+}
+
+static int enumerate_hcd_root_hub(struct libusb_context *ctx, const char *dev_id,
+ uint8_t bus_number, DEVINST devinst)
+{
+ struct libusb_device *dev;
+ struct winusb_device_priv *priv;
+ unsigned long session_id;
+ DEVINST child_devinst;
+
+ if (CM_Get_Child(&child_devinst, devinst, 0) != CR_SUCCESS) {
+ usbi_err(ctx, "could not get child devinst for '%s'", dev_id);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ session_id = (unsigned long)child_devinst;
+ dev = usbi_get_device_by_session_id(ctx, session_id);
+ if (dev == NULL) {
+ usbi_err(ctx, "program assertion failed - HCD '%s' child not found", dev_id);
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ if (dev->bus_number == 0) {
+ // Only do this once
+ usbi_dbg("assigning HCD '%s' bus number %u", dev_id, bus_number);
+ priv = _device_priv(dev);
+ dev->bus_number = bus_number;
+ dev->num_configurations = 1;
+ priv->dev_descriptor.bLength = LIBUSB_DT_DEVICE_SIZE;
+ priv->dev_descriptor.bDescriptorType = LIBUSB_DT_DEVICE;
+ priv->dev_descriptor.bDeviceClass = LIBUSB_CLASS_HUB;
+ priv->dev_descriptor.bNumConfigurations = 1;
+ priv->active_config = 1;
+ priv->root_hub = true;
+ if (sscanf(dev_id, "PCI\\VEN_%04hx&DEV_%04hx%*s", &priv->dev_descriptor.idVendor, &priv->dev_descriptor.idProduct) != 2) {
+ usbi_warn(ctx, "could not infer VID/PID of HCD root hub from '%s'", dev_id);
+ priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub
+ priv->dev_descriptor.idProduct = 1;
+ }
+ }
+
+ libusb_unref_device(dev);
+ return LIBUSB_SUCCESS;
+}
+
+// Returns the api type, or 0 if not found/unsupported
+static void get_api_type(struct libusb_context *ctx, HDEVINFO *dev_info,
+ SP_DEVINFO_DATA *dev_info_data, int *api, int *sub_api)
+{
+ // Precedence for filter drivers vs driver is in the order of this array
+ struct driver_lookup lookup[3] = {
+ {"\0\0", SPDRP_SERVICE, "driver"},
+ {"\0\0", SPDRP_UPPERFILTERS, "upper filter driver"},
+ {"\0\0", SPDRP_LOWERFILTERS, "lower filter driver"}
+ };
+ DWORD size, reg_type;
+ unsigned k, l;
+ int i, j;
+
+ // Check the service & filter names to know the API we should use
+ for (k = 0; k < 3; k++) {
+ if (pSetupDiGetDeviceRegistryPropertyA(*dev_info, dev_info_data, lookup[k].reg_prop,
+ &reg_type, (PBYTE)lookup[k].list, MAX_KEY_LENGTH, &size)) {
+ // Turn the REG_SZ SPDRP_SERVICE into REG_MULTI_SZ
+ if (lookup[k].reg_prop == SPDRP_SERVICE)
+ // our buffers are MAX_KEY_LENGTH + 1 so we can overflow if needed
+ lookup[k].list[strlen(lookup[k].list) + 1] = 0;
+
+ // MULTI_SZ is a pain to work with. Turn it into something much more manageable
+ // NB: none of the driver names we check against contain LIST_SEPARATOR,
+ // (currently ';'), so even if an unsuported one does, it's not an issue
+ for (l = 0; (lookup[k].list[l] != 0) || (lookup[k].list[l + 1] != 0); l++) {
+ if (lookup[k].list[l] == 0)
+ lookup[k].list[l] = LIST_SEPARATOR;
+ }
+ usbi_dbg("%s(s): %s", lookup[k].designation, lookup[k].list);
+ } else {
+ if (GetLastError() != ERROR_INVALID_DATA)
+ usbi_dbg("could not access %s: %s", lookup[k].designation, windows_error_str(0));
+ lookup[k].list[0] = 0;
+ }
+ }
+
+ for (i = 2; i < USB_API_MAX; i++) {
+ for (k = 0; k < 3; k++) {
+ j = get_sub_api(lookup[k].list, i);
+ if (j >= 0) {
+ usbi_dbg("matched %s name against %s", lookup[k].designation,
+ (i != USB_API_WINUSBX) ? usb_api_backend[i].designation : usb_api_backend[i].driver_name_list[j]);
+ *api = i;
+ *sub_api = j;
+ return;
+ }
+ }
+ }
+}
+
+static int set_composite_interface(struct libusb_context *ctx, struct libusb_device *dev,
+ char *dev_interface_path, char *device_id, int api, int sub_api)
+{
+ struct winusb_device_priv *priv = _device_priv(dev);
+ int interface_number;
+ const char *mi_str;
+
+ // Because MI_## are not necessarily in sequential order (some composite
+ // devices will have only MI_00 & MI_03 for instance), we retrieve the actual
+ // interface number from the path's MI value
+ mi_str = strstr(device_id, "MI_");
+ if ((mi_str != NULL) && isdigit(mi_str[3]) && isdigit(mi_str[4])) {
+ interface_number = ((mi_str[3] - '0') * 10) + (mi_str[4] - '0');
+ } else {
+ usbi_warn(ctx, "failure to read interface number for %s, using default value", device_id);
+ interface_number = 0;
+ }
+
+ if (interface_number >= USB_MAXINTERFACES) {
+ usbi_warn(ctx, "interface %d too large - ignoring interface path %s", interface_number, dev_interface_path);
+ return LIBUSB_ERROR_ACCESS;
+ }
+
+ if (priv->usb_interface[interface_number].path != NULL) {
+ if (api == USB_API_HID) {
+ // HID devices can have multiple collections (COL##) for each MI_## interface
+ usbi_dbg("interface[%d] already set - ignoring HID collection: %s",
+ interface_number, device_id);
+ return LIBUSB_ERROR_ACCESS;
+ }
+ // In other cases, just use the latest data
+ safe_free(priv->usb_interface[interface_number].path);
+ }
+
+ usbi_dbg("interface[%d] = %s", interface_number, dev_interface_path);
+ priv->usb_interface[interface_number].path = dev_interface_path;
+ priv->usb_interface[interface_number].apib = &usb_api_backend[api];
+ priv->usb_interface[interface_number].sub_api = sub_api;
+ if ((api == USB_API_HID) && (priv->hid == NULL)) {
+ priv->hid = calloc(1, sizeof(struct hid_device_priv));
+ if (priv->hid == NULL)
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *dev,
+ char *dev_interface_path)
+{
+ int i;
+ struct winusb_device_priv *priv = _device_priv(dev);
+
+ if (priv->hid == NULL) {
+ usbi_err(ctx, "program assertion failed: parent is not HID");
+ return LIBUSB_ERROR_NO_DEVICE;
+ } else if (priv->hid->nb_interfaces == USB_MAXINTERFACES) {
+ usbi_err(ctx, "program assertion failed: max USB interfaces reached for HID device");
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ for (i = 0; i < priv->hid->nb_interfaces; i++) {
+ if ((priv->usb_interface[i].path != NULL) && strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) {
+ usbi_dbg("interface[%d] already set to %s", i, dev_interface_path);
+ return LIBUSB_ERROR_ACCESS;
+ }
+ }
+
+ priv->usb_interface[priv->hid->nb_interfaces].path = dev_interface_path;
+ priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID];
+ usbi_dbg("interface[%u] = %s", priv->hid->nb_interfaces, dev_interface_path);
+ priv->hid->nb_interfaces++;
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * get_device_list: libusb backend device enumeration function
+ */
+static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
+{
+ struct discovered_devs *discdevs;
+ HDEVINFO *dev_info, dev_info_intf, dev_info_enum;
+ SP_DEVINFO_DATA dev_info_data;
+ DWORD _index = 0;
+ GUID hid_guid;
+ int r = LIBUSB_SUCCESS;
+ int api, sub_api;
+ unsigned int pass, i, j;
+ char enumerator[16];
+ char dev_id[MAX_PATH_LENGTH];
+ struct libusb_device *dev, *parent_dev;
+ struct winusb_device_priv *priv, *parent_priv;
+ char *dev_interface_path = NULL;
+ unsigned long session_id;
+ DWORD size, port_nr, reg_type, install_state;
+ HKEY key;
+ WCHAR guid_string_w[MAX_GUID_STRING_LENGTH];
+ GUID *if_guid;
+ LONG s;
+#define HUB_PASS 0
+#define DEV_PASS 1
+#define HCD_PASS 2
+#define GEN_PASS 3
+#define HID_PASS 4
+#define EXT_PASS 5
+ // Keep a list of guids that will be enumerated
+#define GUID_SIZE_STEP 8
+ const GUID **guid_list, **new_guid_list;
+ unsigned int guid_size = GUID_SIZE_STEP;
+ unsigned int nb_guids;
+ // Keep a list of PnP enumerator strings that are found
+ char *usb_enumerator[8] = { "USB" };
+ unsigned int nb_usb_enumerators = 1;
+ unsigned int usb_enum_index = 0;
+ // Keep a list of newly allocated devs to unref
+#define UNREF_SIZE_STEP 16
+ libusb_device **unref_list, **new_unref_list;
+ unsigned int unref_size = UNREF_SIZE_STEP;
+ unsigned int unref_cur = 0;
+
+ // PASS 1 : (re)enumerate HCDs (allows for HCD hotplug)
+ // PASS 2 : (re)enumerate HUBS
+ // PASS 3 : (re)enumerate generic USB devices (including driverless)
+ // and list additional USB device interface GUIDs to explore
+ // PASS 4 : (re)enumerate master USB devices that have a device interface
+ // PASS 5+: (re)enumerate device interfaced GUIDs (including HID) and
+ // set the device interfaces.
+
+ // Init the GUID table
+ guid_list = malloc(guid_size * sizeof(void *));
+ if (guid_list == NULL) {
+ usbi_err(ctx, "failed to alloc guid list");
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ guid_list[HUB_PASS] = &GUID_DEVINTERFACE_USB_HUB;
+ guid_list[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE;
+ guid_list[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER;
+ guid_list[GEN_PASS] = NULL;
+ if (api_hid_available) {
+ HidD_GetHidGuid(&hid_guid);
+ guid_list[HID_PASS] = &hid_guid;
+ } else {
+ guid_list[HID_PASS] = NULL;
+ }
+ nb_guids = EXT_PASS;
+
+ unref_list = malloc(unref_size * sizeof(void *));
+ if (unref_list == NULL) {
+ usbi_err(ctx, "failed to alloc unref list");
+ free((void *)guid_list);
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ dev_info_intf = pSetupDiGetClassDevsA(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+ if (dev_info_intf == INVALID_HANDLE_VALUE) {
+ usbi_err(ctx, "failed to obtain device info list: %s", windows_error_str(0));
+ free(unref_list);
+ free((void *)guid_list);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ for (pass = 0; ((pass < nb_guids) && (r == LIBUSB_SUCCESS)); pass++) {
+//#define ENUM_DEBUG
+#if defined(ENABLE_LOGGING) && defined(ENUM_DEBUG)
+ const char * const passname[] = {"HUB", "DEV", "HCD", "GEN", "HID", "EXT"};
+ usbi_dbg("#### PROCESSING %ss %s", passname[MIN(pass, EXT_PASS)], guid_to_string(guid_list[pass]));
+#endif
+ if ((pass == HID_PASS) && (guid_list[HID_PASS] == NULL))
+ continue;
+
+ dev_info = (pass != GEN_PASS) ? &dev_info_intf : &dev_info_enum;
+
+ for (i = 0; ; i++) {
+ // safe loop: free up any (unprotected) dynamic resource
+ // NB: this is always executed before breaking the loop
+ safe_free(dev_interface_path);
+ priv = parent_priv = NULL;
+ dev = parent_dev = NULL;
+
+ // Safe loop: end of loop conditions
+ if (r != LIBUSB_SUCCESS)
+ break;
+
+ if ((pass == HCD_PASS) && (i == UINT8_MAX)) {
+ usbi_warn(ctx, "program assertion failed - found more than %u buses, skipping the rest.", UINT8_MAX);
+ break;
+ }
+
+ if (pass != GEN_PASS) {
+ // Except for GEN, all passes deal with device interfaces
+ r = get_interface_details(ctx, *dev_info, &dev_info_data, guid_list[pass], &_index, &dev_interface_path);
+ if ((r != LIBUSB_SUCCESS) || (dev_interface_path == NULL)) {
+ _index = 0;
+ break;
+ }
+ } else {
+ // Workaround for a Nec/Renesas USB 3.0 driver bug where root hubs are
+ // being listed under the "NUSB3" PnP Symbolic Name rather than "USB".
+ // The Intel USB 3.0 driver behaves similar, but uses "IUSB3"
+ // The Intel Alpine Ridge USB 3.1 driver uses "IARUSB3"
+ for (; usb_enum_index < nb_usb_enumerators; usb_enum_index++) {
+ if (get_devinfo_data(ctx, dev_info, &dev_info_data, usb_enumerator[usb_enum_index], i))
+ break;
+ i = 0;
+ }
+ if (usb_enum_index == nb_usb_enumerators)
+ break;
+ }
+
+ // Read the Device ID path
+ if (!pSetupDiGetDeviceInstanceIdA(*dev_info, &dev_info_data, dev_id, sizeof(dev_id), NULL)) {
+ usbi_warn(ctx, "could not read the device instance ID for devInst %X, skipping",
+ dev_info_data.DevInst);
+ continue;
+ }
+
+#ifdef ENUM_DEBUG
+ usbi_dbg("PRO: %s", dev_id);
+#endif
+
+ // Set API to use or get additional data from generic pass
+ api = USB_API_UNSUPPORTED;
+ sub_api = SUB_API_NOTSET;
+ switch (pass) {
+ case HCD_PASS:
+ break;
+ case HUB_PASS:
+ api = USB_API_HUB;
+ // Fetch the PnP enumerator class for this hub
+ // This will allow us to enumerate all classes during the GEN pass
+ if (!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME,
+ NULL, (PBYTE)enumerator, sizeof(enumerator), NULL)) {
+ usbi_err(ctx, "could not read enumerator string for device '%s': %s", dev_id, windows_error_str(0));
+ LOOP_BREAK(LIBUSB_ERROR_OTHER);
+ }
+ for (j = 0; j < nb_usb_enumerators; j++) {
+ if (strcmp(usb_enumerator[j], enumerator) == 0)
+ break;
+ }
+ if (j == nb_usb_enumerators) {
+ usbi_dbg("found new PnP enumerator string '%s'", enumerator);
+ if (nb_usb_enumerators < ARRAYSIZE(usb_enumerator)) {
+ usb_enumerator[nb_usb_enumerators] = _strdup(enumerator);
+ if (usb_enumerator[nb_usb_enumerators] != NULL) {
+ nb_usb_enumerators++;
+ } else {
+ usbi_err(ctx, "could not allocate enumerator string '%s'", enumerator);
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+ }
+ } else {
+ usbi_warn(ctx, "too many enumerator strings, some devices may not be accessible");
+ }
+ }
+ break;
+ case GEN_PASS:
+ // We use the GEN pass to detect driverless devices...
+ if (!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_DRIVER,
+ NULL, NULL, 0, NULL) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
+ usbi_info(ctx, "The following device has no driver: '%s'", dev_id);
+ usbi_info(ctx, "libusb will not be able to access it");
+ }
+ // ...and to add the additional device interface GUIDs
+ key = pSetupDiOpenDevRegKey(*dev_info, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
+ if (key == INVALID_HANDLE_VALUE)
+ break;
+ // Look for both DeviceInterfaceGUIDs *and* DeviceInterfaceGUID, in that order
+ size = sizeof(guid_string_w);
+ s = pRegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, &reg_type,
+ (LPBYTE)guid_string_w, &size);
+ if (s == ERROR_FILE_NOT_FOUND)
+ s = pRegQueryValueExW(key, L"DeviceInterfaceGUID", NULL, &reg_type,
+ (LPBYTE)guid_string_w, &size);
+ pRegCloseKey(key);
+ if ((s == ERROR_SUCCESS) &&
+ (((reg_type == REG_SZ) && (size == (sizeof(guid_string_w) - sizeof(WCHAR)))) ||
+ ((reg_type == REG_MULTI_SZ) && (size == sizeof(guid_string_w))))) {
+ if (nb_guids == guid_size) {
+ new_guid_list = realloc((void *)guid_list, (guid_size + GUID_SIZE_STEP) * sizeof(void *));
+ if (new_guid_list == NULL) {
+ usbi_err(ctx, "failed to realloc guid list");
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+ }
+ guid_list = new_guid_list;
+ guid_size += GUID_SIZE_STEP;
+ }
+ if_guid = malloc(sizeof(*if_guid));
+ if (if_guid == NULL) {
+ usbi_err(ctx, "failed to alloc if_guid");
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+ }
+ if (pIIDFromString(guid_string_w, if_guid) != 0) {
+ usbi_warn(ctx, "device '%s' has malformed DeviceInterfaceGUID string, skipping", dev_id);
+ free(if_guid);
+ } else {
+ // Check if we've already seen this GUID
+ for (j = EXT_PASS; j < nb_guids; j++) {
+ if (memcmp(guid_list[j], if_guid, sizeof(*if_guid)) == 0)
+ break;
+ }
+ if (j == nb_guids) {
+ usbi_dbg("extra GUID: %s", guid_to_string(if_guid));
+ guid_list[nb_guids++] = if_guid;
+ } else {
+ // Duplicate, ignore
+ free(if_guid);
+ }
+ }
+ } else if (s == ERROR_SUCCESS) {
+ usbi_warn(ctx, "unexpected type/size of DeviceInterfaceGUID for '%s'", dev_id);
+ }
+ break;
+ case HID_PASS:
+ api = USB_API_HID;
+ break;
+ default:
+ // Get the API type (after checking that the driver installation is OK)
+ if ((!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_INSTALL_STATE,
+ NULL, (PBYTE)&install_state, sizeof(install_state), &size)) || (size != sizeof(install_state))) {
+ usbi_warn(ctx, "could not detect installation state of driver for '%s': %s",
+ dev_id, windows_error_str(0));
+ } else if (install_state != 0) {
+ usbi_warn(ctx, "driver for device '%s' is reporting an issue (code: %u) - skipping",
+ dev_id, (unsigned int)install_state);
+ continue;
+ }
+ get_api_type(ctx, dev_info, &dev_info_data, &api, &sub_api);
+ break;
+ }
+
+ // Find parent device (for the passes that need it)
+ if (pass >= GEN_PASS) {
+ parent_dev = get_ancestor(ctx, dev_info_data.DevInst, NULL);
+ if (parent_dev == NULL) {
+ // Root hubs will not have a parent
+ dev = usbi_get_device_by_session_id(ctx, (unsigned long)dev_info_data.DevInst);
+ if (dev != NULL) {
+ priv = _device_priv(dev);
+ if (priv->root_hub)
+ goto track_unref;
+ libusb_unref_device(dev);
+ }
+
+ usbi_dbg("unlisted ancestor for '%s' (non USB HID, newly connected, etc.) - ignoring", dev_id);
+ continue;
+ }
+
+ parent_priv = _device_priv(parent_dev);
+ // virtual USB devices are also listed during GEN - don't process these yet
+ if ((pass == GEN_PASS) && (parent_priv->apib->id != USB_API_HUB)) {
+ libusb_unref_device(parent_dev);
+ continue;
+ }
+ }
+
+ // Create new or match existing device, using the devInst as session id
+ if ((pass <= GEN_PASS) && (pass != HCD_PASS)) { // For subsequent passes, we'll lookup the parent
+ // These are the passes that create "new" devices
+ session_id = (unsigned long)dev_info_data.DevInst;
+ dev = usbi_get_device_by_session_id(ctx, session_id);
+ if (dev == NULL) {
+ alloc_device:
+ usbi_dbg("allocating new device for session [%lX]", session_id);
+ dev = usbi_alloc_device(ctx, session_id);
+ if (dev == NULL)
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+
+ priv = winusb_device_priv_init(dev);
+ priv->dev_id = _strdup(dev_id);
+ if (priv->dev_id == NULL) {
+ libusb_unref_device(dev);
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+ }
+ } else {
+ usbi_dbg("found existing device for session [%lX]", session_id);
+
+ priv = _device_priv(dev);
+ if (strcmp(priv->dev_id, dev_id) != 0) {
+ usbi_dbg("device instance ID for session [%lX] changed", session_id);
+ usbi_disconnect_device(dev);
+ libusb_unref_device(dev);
+ goto alloc_device;
+ }
+ }
+
+ track_unref:
+ // Keep track of devices that need unref
+ if (unref_cur == unref_size) {
+ new_unref_list = realloc(unref_list, (unref_size + UNREF_SIZE_STEP) * sizeof(void *));
+ if (new_unref_list == NULL) {
+ usbi_err(ctx, "could not realloc list for unref - aborting");
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+ }
+ unref_list = new_unref_list;
+ unref_size += UNREF_SIZE_STEP;
+ }
+ unref_list[unref_cur++] = dev;
+ }
+
+ // Setup device
+ switch (pass) {
+ case HUB_PASS:
+ case DEV_PASS:
+ // If the device has already been setup, don't do it again
+ if (priv->path != NULL)
+ break;
+ // Take care of API initialization
+ priv->path = dev_interface_path;
+ dev_interface_path = NULL;
+ priv->apib = &usb_api_backend[api];
+ priv->sub_api = sub_api;
+ switch (api) {
+ case USB_API_COMPOSITE:
+ case USB_API_HUB:
+ break;
+ case USB_API_HID:
+ priv->hid = calloc(1, sizeof(struct hid_device_priv));
+ if (priv->hid == NULL)
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+ break;
+ default:
+ // For other devices, the first interface is the same as the device
+ priv->usb_interface[0].path = _strdup(priv->path);
+ if (priv->usb_interface[0].path == NULL)
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+ // The following is needed if we want API calls to work for both simple
+ // and composite devices.
+ for (j = 0; j < USB_MAXINTERFACES; j++)
+ priv->usb_interface[j].apib = &usb_api_backend[api];
+ break;
+ }
+ break;
+ case HCD_PASS:
+ r = enumerate_hcd_root_hub(ctx, dev_id, (uint8_t)(i + 1), dev_info_data.DevInst);
+ break;
+ case GEN_PASS:
+ // The SPDRP_ADDRESS for USB devices is the device port number on the hub
+ port_nr = 0;
+ if (!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_ADDRESS,
+ NULL, (PBYTE)&port_nr, sizeof(port_nr), &size) || (size != sizeof(port_nr)))
+ usbi_warn(ctx, "could not retrieve port number for device '%s': %s", dev_id, windows_error_str(0));
+ r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_info_data.DevInst);
+ if (r == LIBUSB_SUCCESS) {
+ // Append device to the list of discovered devices
+ discdevs = discovered_devs_append(*_discdevs, dev);
+ if (!discdevs)
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+
+ *_discdevs = discdevs;
+ } else if (r == LIBUSB_ERROR_NO_DEVICE) {
+ // This can occur if the device was disconnected but Windows hasn't
+ // refreshed its enumeration yet - in that case, we ignore the device
+ r = LIBUSB_SUCCESS;
+ }
+ break;
+ default: // HID_PASS and later
+ if (parent_priv->apib->id == USB_API_HID || parent_priv->apib->id == USB_API_COMPOSITE) {
+ if (parent_priv->apib->id == USB_API_HID) {
+ usbi_dbg("setting HID interface for [%lX]:", parent_dev->session_data);
+ r = set_hid_interface(ctx, parent_dev, dev_interface_path);
+ } else {
+ usbi_dbg("setting composite interface for [%lX]:", parent_dev->session_data);
+ r = set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id, api, sub_api);
+ }
+ switch (r) {
+ case LIBUSB_SUCCESS:
+ dev_interface_path = NULL;
+ break;
+ case LIBUSB_ERROR_ACCESS:
+ // interface has already been set => make sure dev_interface_path is freed then
+ r = LIBUSB_SUCCESS;
+ break;
+ default:
+ LOOP_BREAK(r);
+ break;
+ }
+ }
+ libusb_unref_device(parent_dev);
+ break;
+ }
+ }
+ }
+
+ pSetupDiDestroyDeviceInfoList(dev_info_intf);
+
+ // Free any additional GUIDs
+ for (pass = EXT_PASS; pass < nb_guids; pass++)
+ free((void *)guid_list[pass]);
+ free((void *)guid_list);
+
+ // Free any PnP enumerator strings
+ for (i = 1; i < nb_usb_enumerators; i++)
+ free(usb_enumerator[i]);
+
+ // Unref newly allocated devs
+ for (i = 0; i < unref_cur; i++)
+ libusb_unref_device(unref_list[i]);
+ free(unref_list);
+
+ return r;
+}
+
+static int winusb_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer)
+{
+ struct winusb_device_priv *priv = _device_priv(dev);
+
+ memcpy(buffer, &priv->dev_descriptor, DEVICE_DESC_LENGTH);
+ return LIBUSB_SUCCESS;
+}
+
+static int winusb_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len)
+{
+ struct winusb_device_priv *priv = _device_priv(dev);
+ PUSB_CONFIGURATION_DESCRIPTOR config_header;
+ size_t size;
+
+ // config index is zero based
+ if (config_index >= dev->num_configurations)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ if ((priv->config_descriptor == NULL) || (priv->config_descriptor[config_index] == NULL))
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ config_header = priv->config_descriptor[config_index];
+
+ size = MIN(config_header->wTotalLength, len);
+ memcpy(buffer, priv->config_descriptor[config_index], size);
+ return (int)size;
+}
+
+static int winusb_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
+ unsigned char **buffer)
+{
+ struct winusb_device_priv *priv = _device_priv(dev);
+ PUSB_CONFIGURATION_DESCRIPTOR config_header;
+ uint8_t index;
+
+ if (priv->config_descriptor == NULL)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ for (index = 0; index < dev->num_configurations; index++) {
+ config_header = priv->config_descriptor[index];
+ if (config_header == NULL)
+ continue;
+ if (config_header->bConfigurationValue == bConfigurationValue) {
+ *buffer = (unsigned char *)priv->config_descriptor[index];
+ return (int)config_header->wTotalLength;
+ }
+ }
+
+ return LIBUSB_ERROR_NOT_FOUND;
+}
+
+/*
+ * return the cached copy of the active config descriptor
+ */
+static int winusb_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len)
+{
+ struct winusb_device_priv *priv = _device_priv(dev);
+ unsigned char *config_desc;
+ int r;
+
+ if (priv->active_config == 0)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ r = winusb_get_config_descriptor_by_value(dev, priv->active_config, &config_desc);
+ if (r < 0)
+ return r;
+
+ len = MIN((size_t)r, len);
+ memcpy(buffer, config_desc, len);
+ return (int)len;
+}
+
+static int winusb_open(struct libusb_device_handle *dev_handle)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+
+ CHECK_SUPPORTED_API(priv->apib, open);
+
+ return priv->apib->open(SUB_API_NOTSET, dev_handle);
+}
+
+static void winusb_close(struct libusb_device_handle *dev_handle)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+
+ if (priv->apib->close)
+ priv->apib->close(SUB_API_NOTSET, dev_handle);
+}
+
+static int winusb_get_configuration(struct libusb_device_handle *dev_handle, int *config)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+
+ if (priv->active_config == 0) {
+ *config = 0;
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ *config = priv->active_config;
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * from http://msdn.microsoft.com/en-us/library/ms793522.aspx: "The port driver
+ * does not currently expose a service that allows higher-level drivers to set
+ * the configuration."
+ */
+static int winusb_set_configuration(struct libusb_device_handle *dev_handle, int config)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ int r = LIBUSB_SUCCESS;
+
+ if (config >= USB_MAXCONFIG)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_OUT |
+ LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
+ LIBUSB_REQUEST_SET_CONFIGURATION, (uint16_t)config,
+ 0, NULL, 0, 1000);
+
+ if (r == LIBUSB_SUCCESS)
+ priv->active_config = (uint8_t)config;
+
+ return r;
+}
+
+static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ int r;
+
+ CHECK_SUPPORTED_API(priv->apib, claim_interface);
+
+ safe_free(priv->usb_interface[iface].endpoint);
+ priv->usb_interface[iface].nb_endpoints = 0;
+
+ r = priv->apib->claim_interface(SUB_API_NOTSET, dev_handle, iface);
+
+ if (r == LIBUSB_SUCCESS)
+ r = windows_assign_endpoints(dev_handle, iface, 0);
+
+ return r;
+}
+
+static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ int r;
+
+ CHECK_SUPPORTED_API(priv->apib, set_interface_altsetting);
+
+ safe_free(priv->usb_interface[iface].endpoint);
+ priv->usb_interface[iface].nb_endpoints = 0;
+
+ r = priv->apib->set_interface_altsetting(SUB_API_NOTSET, dev_handle, iface, altsetting);
+
+ if (r == LIBUSB_SUCCESS)
+ r = windows_assign_endpoints(dev_handle, iface, altsetting);
+
+ return r;
+}
+
+static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+
+ CHECK_SUPPORTED_API(priv->apib, release_interface);
+
+ return priv->apib->release_interface(SUB_API_NOTSET, dev_handle, iface);
+}
+
+static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+
+ CHECK_SUPPORTED_API(priv->apib, clear_halt);
+
+ return priv->apib->clear_halt(SUB_API_NOTSET, dev_handle, endpoint);
+}
+
+static int winusb_reset_device(struct libusb_device_handle *dev_handle)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+
+ CHECK_SUPPORTED_API(priv->apib, reset_device);
+
+ return priv->apib->reset_device(SUB_API_NOTSET, dev_handle);
+}
+
+static void winusb_destroy_device(struct libusb_device *dev)
+{
+ winusb_device_priv_release(dev);
+}
+
+static void winusb_clear_transfer_priv(struct usbi_transfer *itransfer)
+{
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+
+ usbi_close(transfer_priv->pollable_fd.fd);
+ transfer_priv->pollable_fd = INVALID_WINFD;
+ transfer_priv->handle = NULL;
+ safe_free(transfer_priv->hid_buffer);
+ safe_free(transfer_priv->iso_context);
+
+ // When auto claim is in use, attempt to release the auto-claimed interface
+ auto_release(itransfer);
+}
+
+static int do_submit_transfer(struct usbi_transfer *itransfer, short events,
+ int (*transfer_fn)(int, struct usbi_transfer *))
+{
+ struct libusb_context *ctx = ITRANSFER_CTX(itransfer);
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct winfd wfd;
+ int r;
+
+ wfd = usbi_create_fd();
+ if (wfd.fd < 0)
+ return LIBUSB_ERROR_NO_MEM;
+
+ r = usbi_add_pollfd(ctx, wfd.fd, events);
+ if (r) {
+ usbi_close(wfd.fd);
+ return r;
+ }
+
+ // Use transfer_priv to store data needed for async polling
+ transfer_priv->pollable_fd = wfd;
+
+ r = transfer_fn(SUB_API_NOTSET, itransfer);
+
+ if ((r != LIBUSB_SUCCESS) && (r != LIBUSB_ERROR_OVERFLOW)) {
+ usbi_remove_pollfd(ctx, wfd.fd);
+ usbi_close(wfd.fd);
+ transfer_priv->pollable_fd = INVALID_WINFD;
+ }
+
+ return r;
+}
+
+static int winusb_submit_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ int (*transfer_fn)(int, struct usbi_transfer *);
+ short events;
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ events = (transfer->buffer[0] & LIBUSB_ENDPOINT_IN) ? POLLIN : POLLOUT;
+ transfer_fn = priv->apib->submit_control_transfer;
+ break;
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
+ transfer_fn = priv->apib->submit_bulk_transfer;
+ break;
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ events = IS_XFERIN(transfer) ? POLLIN : POLLOUT;
+ transfer_fn = priv->apib->submit_iso_transfer;
+ break;
+ case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ default:
+ usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ if (transfer_fn == NULL) {
+ usbi_warn(TRANSFER_CTX(transfer),
+ "unsupported transfer type %d (unrecognized device driver)",
+ transfer->type);
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ }
+
+ return do_submit_transfer(itransfer, events, transfer_fn);
+}
+
+static int windows_abort_control(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+
+ CHECK_SUPPORTED_API(priv->apib, abort_control);
+
+ return priv->apib->abort_control(SUB_API_NOTSET, itransfer);
+}
+
+static int windows_abort_transfers(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+
+ CHECK_SUPPORTED_API(priv->apib, abort_transfers);
+
+ return priv->apib->abort_transfers(SUB_API_NOTSET, itransfer);
+}
+
+static int winusb_cancel_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ return windows_abort_control(itransfer);
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ return windows_abort_transfers(itransfer);
+ case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ default:
+ usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+}
+
+static int winusb_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size);
+}
+
+static int winusb_get_transfer_fd(struct usbi_transfer *itransfer)
+{
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ return transfer_priv->pollable_fd.fd;
+}
+
+static void winusb_get_overlapped_result(struct usbi_transfer *itransfer,
+ DWORD *io_result, DWORD *io_size)
+{
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct winfd *pollable_fd = &transfer_priv->pollable_fd;
+
+ if (HasOverlappedIoCompletedSync(pollable_fd->overlapped)) {
+ *io_result = NO_ERROR;
+ *io_size = (DWORD)pollable_fd->overlapped->InternalHigh;
+ } else if (GetOverlappedResult(transfer_priv->handle, pollable_fd->overlapped, io_size, FALSE)) {
+ // Regular async overlapped
+ *io_result = NO_ERROR;
+ } else {
+ *io_result = GetLastError();
+ }
+}
+
+// NB: MSVC6 does not support named initializers.
+const struct windows_backend winusb_backend = {
+ winusb_init,
+ winusb_exit,
+ winusb_get_device_list,
+ winusb_open,
+ winusb_close,
+ winusb_get_device_descriptor,
+ winusb_get_active_config_descriptor,
+ winusb_get_config_descriptor,
+ winusb_get_config_descriptor_by_value,
+ winusb_get_configuration,
+ winusb_set_configuration,
+ winusb_claim_interface,
+ winusb_release_interface,
+ winusb_set_interface_altsetting,
+ winusb_clear_halt,
+ winusb_reset_device,
+ winusb_destroy_device,
+ winusb_submit_transfer,
+ winusb_cancel_transfer,
+ winusb_clear_transfer_priv,
+ winusb_copy_transfer_data,
+ winusb_get_transfer_fd,
+ winusb_get_overlapped_result,
+};
+
+/*
+ * USB API backends
+ */
+
+static const char * const composite_driver_names[] = {"USBCCGP"};
+static const char * const winusbx_driver_names[] = {"libusbK", "libusb0", "WinUSB"};
+static const char * const hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"};
+const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
+ {
+ USB_API_UNSUPPORTED,
+ "Unsupported API",
+ // No supported operations
+ },
+ {
+ USB_API_HUB,
+ "HUB API",
+ // No supported operations
+ },
+ {
+ USB_API_COMPOSITE,
+ "Composite API",
+ composite_driver_names,
+ ARRAYSIZE(composite_driver_names),
+ NULL, /* init */
+ NULL, /* exit */
+ composite_open,
+ composite_close,
+ NULL, /* configure_endpoints */
+ composite_claim_interface,
+ composite_set_interface_altsetting,
+ composite_release_interface,
+ composite_clear_halt,
+ composite_reset_device,
+ composite_submit_bulk_transfer,
+ composite_submit_iso_transfer,
+ composite_submit_control_transfer,
+ composite_abort_control,
+ composite_abort_transfers,
+ composite_copy_transfer_data,
+ },
+ {
+ USB_API_WINUSBX,
+ "WinUSB-like APIs",
+ winusbx_driver_names,
+ ARRAYSIZE(winusbx_driver_names),
+ winusbx_init,
+ winusbx_exit,
+ winusbx_open,
+ winusbx_close,
+ winusbx_configure_endpoints,
+ winusbx_claim_interface,
+ winusbx_set_interface_altsetting,
+ winusbx_release_interface,
+ winusbx_clear_halt,
+ winusbx_reset_device,
+ winusbx_submit_bulk_transfer,
+ winusbx_submit_iso_transfer,
+ winusbx_submit_control_transfer,
+ winusbx_abort_control,
+ winusbx_abort_transfers,
+ winusbx_copy_transfer_data,
+ },
+ {
+ USB_API_HID,
+ "HID API",
+ // No supported operations
+ },
+};
+
+
+/*
+ * WinUSB-like (WinUSB, libusb0/libusbK through libusbk DLL) API functions
+ */
+#define WinUSBX_Set(fn) \
+ do { \
+ if (native_winusb) \
+ WinUSBX[i].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn); \
+ else \
+ pLibK_GetProcAddress((PVOID *)&WinUSBX[i].fn, i, KUSB_FNID_##fn); \
+ } while (0)
+
+static int winusbx_init(struct libusb_context *ctx)
+{
+ HMODULE h;
+ bool native_winusb;
+ int i;
+ KLIB_VERSION LibK_Version;
+ LibK_GetProcAddress_t pLibK_GetProcAddress = NULL;
+ LibK_GetVersion_t pLibK_GetVersion;
+
+ h = LoadLibraryA("libusbK");
+
+ if (h == NULL) {
+ usbi_info(ctx, "libusbK DLL is not available, will use native WinUSB");
+ h = LoadLibraryA("WinUSB");
+
+ if (h == NULL) {
+ usbi_warn(ctx, "WinUSB DLL is not available either, "
+ "you will not be able to access devices outside of enumeration");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+ } else {
+ usbi_dbg("using libusbK DLL for universal access");
+ pLibK_GetVersion = (LibK_GetVersion_t)GetProcAddress(h, "LibK_GetVersion");
+ if (pLibK_GetVersion != NULL) {
+ pLibK_GetVersion(&LibK_Version);
+ usbi_dbg("libusbK version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor,
+ LibK_Version.Micro, LibK_Version.Nano);
+ }
+ pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(h, "LibK_GetProcAddress");
+ if (pLibK_GetProcAddress == NULL) {
+ usbi_err(ctx, "LibK_GetProcAddress() not found in libusbK DLL");
+ FreeLibrary(h);
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+ }
+
+ native_winusb = (pLibK_GetProcAddress == NULL);
+ for (i = 0; i < SUB_API_MAX; i++) {
+ WinUSBX_Set(AbortPipe);
+ WinUSBX_Set(ControlTransfer);
+ WinUSBX_Set(FlushPipe);
+ WinUSBX_Set(Free);
+ WinUSBX_Set(GetAssociatedInterface);
+ WinUSBX_Set(Initialize);
+ WinUSBX_Set(ReadPipe);
+ if (!native_winusb)
+ WinUSBX_Set(ResetDevice);
+ WinUSBX_Set(ResetPipe);
+ WinUSBX_Set(SetCurrentAlternateSetting);
+ WinUSBX_Set(SetPipePolicy);
+ WinUSBX_Set(WritePipe);
+ WinUSBX_Set(IsoReadPipe);
+ WinUSBX_Set(IsoWritePipe);
+
+ if (WinUSBX[i].Initialize != NULL) {
+ WinUSBX[i].initialized = true;
+ // Assume driver supports CancelIoEx() if it is available
+ WinUSBX[i].CancelIoEx_supported = (pCancelIoEx != NULL);
+ usbi_dbg("initalized sub API %s", winusbx_driver_names[i]);
+ } else {
+ usbi_warn(ctx, "Failed to initalize sub API %s", winusbx_driver_names[i]);
+ WinUSBX[i].initialized = false;
+ }
+ }
+
+ WinUSBX_handle = h;
+ return LIBUSB_SUCCESS;
+}
+
+static void winusbx_exit(void)
+{
+ if (WinUSBX_handle != NULL) {
+ FreeLibrary(WinUSBX_handle);
+ WinUSBX_handle = NULL;
+
+ /* Reset the WinUSBX API structures */
+ memset(&WinUSBX, 0, sizeof(WinUSBX));
+ }
+}
+
+// NB: open and close must ensure that they only handle interface of
+// the right API type, as these functions can be called wholesale from
+// composite_open(), with interfaces belonging to different APIs
+static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
+ HANDLE file_handle;
+ int i;
+
+ CHECK_WINUSBX_AVAILABLE(sub_api);
+
+ // WinUSB requires a separate handle for each interface
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if ((priv->usb_interface[i].path != NULL)
+ && (priv->usb_interface[i].apib->id == USB_API_WINUSBX)) {
+ file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+ if (file_handle == INVALID_HANDLE_VALUE) {
+ usbi_err(ctx, "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0));
+ switch (GetLastError()) {
+ case ERROR_FILE_NOT_FOUND: // The device was disconnected
+ return LIBUSB_ERROR_NO_DEVICE;
+ case ERROR_ACCESS_DENIED:
+ return LIBUSB_ERROR_ACCESS;
+ default:
+ return LIBUSB_ERROR_IO;
+ }
+ }
+ handle_priv->interface_handle[i].dev_handle = file_handle;
+ }
+ }
+ return LIBUSB_SUCCESS;
+}
+
+static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle)
+{
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ HANDLE handle;
+ int i;
+
+ if (sub_api == SUB_API_NOTSET)
+ sub_api = priv->sub_api;
+
+ if (!WinUSBX[sub_api].initialized)
+ return;
+
+ if (priv->apib->id == USB_API_COMPOSITE) {
+ // If this is a composite device, just free and close all WinUSB-like
+ // interfaces directly (each is independent and not associated with another)
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if (priv->usb_interface[i].apib->id == USB_API_WINUSBX) {
+ handle = handle_priv->interface_handle[i].api_handle;
+ if (HANDLE_VALID(handle))
+ WinUSBX[sub_api].Free(handle);
+
+ handle = handle_priv->interface_handle[i].dev_handle;
+ if (HANDLE_VALID(handle))
+ CloseHandle(handle);
+ }
+ }
+ } else {
+ // If this is a WinUSB device, free all interfaces above interface 0,
+ // then free and close interface 0 last
+ for (i = 1; i < USB_MAXINTERFACES; i++) {
+ handle = handle_priv->interface_handle[i].api_handle;
+ if (HANDLE_VALID(handle))
+ WinUSBX[sub_api].Free(handle);
+ }
+ handle = handle_priv->interface_handle[0].api_handle;
+ if (HANDLE_VALID(handle))
+ WinUSBX[sub_api].Free(handle);
+
+ handle = handle_priv->interface_handle[0].dev_handle;
+ if (HANDLE_VALID(handle))
+ CloseHandle(handle);
+ }
+}
+
+static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface)
+{
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ HANDLE winusb_handle = handle_priv->interface_handle[iface].api_handle;
+ UCHAR policy;
+ ULONG timeout = 0;
+ uint8_t endpoint_address;
+ int i;
+
+ CHECK_WINUSBX_AVAILABLE(sub_api);
+
+ // With handle and enpoints set (in parent), we can setup the default pipe properties
+ // see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx
+ for (i = -1; i < priv->usb_interface[iface].nb_endpoints; i++) {
+ endpoint_address = (i == -1) ? 0 : priv->usb_interface[iface].endpoint[i];
+ if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
+ PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout))
+ usbi_dbg("failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address);
+
+ if ((i == -1) || (sub_api == SUB_API_LIBUSB0))
+ continue; // Other policies don't apply to control endpoint or libusb0
+
+ policy = false;
+ if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
+ SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy))
+ usbi_dbg("failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address);
+
+ if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
+ IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy))
+ usbi_dbg("failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address);
+
+ policy = true;
+ /* ALLOW_PARTIAL_READS must be enabled due to likely libusbK bug. See:
+ https://sourceforge.net/mailarchive/message.php?msg_id=29736015 */
+ if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
+ ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy))
+ usbi_dbg("failed to enable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address);
+
+ if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
+ AUTO_CLEAR_STALL, sizeof(UCHAR), &policy))
+ usbi_dbg("failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address);
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE);
+ SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL;
+ HDEVINFO dev_info = INVALID_HANDLE_VALUE;
+ SP_DEVINFO_DATA dev_info_data;
+ char *dev_path_no_guid = NULL;
+ char filter_path[] = "\\\\.\\libusb0-0000";
+ bool found_filter = false;
+ HANDLE file_handle, winusb_handle;
+ DWORD err;
+ int i;
+
+ CHECK_WINUSBX_AVAILABLE(sub_api);
+
+ // If the device is composite, but using the default Windows composite parent driver (usbccgp)
+ // or if it's the first WinUSB-like interface, we get a handle through Initialize().
+ if ((is_using_usbccgp) || (iface == 0)) {
+ // composite device (independent interfaces) or interface 0
+ file_handle = handle_priv->interface_handle[iface].dev_handle;
+ if (!HANDLE_VALID(file_handle))
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ if (!WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
+ handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
+ err = GetLastError();
+ switch (err) {
+ case ERROR_BAD_COMMAND:
+ // The device was disconnected
+ usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(0));
+ return LIBUSB_ERROR_NO_DEVICE;
+ default:
+ // it may be that we're using the libusb0 filter driver.
+ // TODO: can we move this whole business into the K/0 DLL?
+ for (i = 0; ; i++) {
+ safe_free(dev_interface_details);
+ safe_free(dev_path_no_guid);
+
+ dev_interface_details = get_interface_details_filter(ctx, &dev_info, &dev_info_data, &GUID_DEVINTERFACE_LIBUSB0_FILTER, i, filter_path);
+ if ((found_filter) || (dev_interface_details == NULL))
+ break;
+
+ // ignore GUID part
+ dev_path_no_guid = sanitize_path(strtok(dev_interface_details->DevicePath, "{"));
+ if (dev_path_no_guid == NULL)
+ continue;
+
+ if (strncmp(dev_path_no_guid, priv->usb_interface[iface].path, strlen(dev_path_no_guid)) == 0) {
+ file_handle = CreateFileA(filter_path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+ if (file_handle != INVALID_HANDLE_VALUE) {
+ if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
+ // Replace the existing file handle with the working one
+ CloseHandle(handle_priv->interface_handle[iface].dev_handle);
+ handle_priv->interface_handle[iface].dev_handle = file_handle;
+ found_filter = true;
+ } else {
+ usbi_err(ctx, "could not initialize filter driver for %s", filter_path);
+ CloseHandle(file_handle);
+ }
+ } else {
+ usbi_err(ctx, "could not open device %s: %s", filter_path, windows_error_str(0));
+ }
+ }
+ }
+ free(dev_interface_details);
+ if (!found_filter) {
+ usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(err));
+ return LIBUSB_ERROR_ACCESS;
+ }
+ }
+ }
+ handle_priv->interface_handle[iface].api_handle = winusb_handle;
+ } else {
+ // For all other interfaces, use GetAssociatedInterface()
+ winusb_handle = handle_priv->interface_handle[0].api_handle;
+ // It is a requirement for multiple interface devices on Windows that, to you
+ // must first claim the first interface before you claim the others
+ if (!HANDLE_VALID(winusb_handle)) {
+ file_handle = handle_priv->interface_handle[0].dev_handle;
+ if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
+ handle_priv->interface_handle[0].api_handle = winusb_handle;
+ usbi_warn(ctx, "auto-claimed interface 0 (required to claim %d with WinUSB)", iface);
+ } else {
+ usbi_warn(ctx, "failed to auto-claim interface 0 (required to claim %d with WinUSB): %s", iface, windows_error_str(0));
+ return LIBUSB_ERROR_ACCESS;
+ }
+ }
+ if (!WinUSBX[sub_api].GetAssociatedInterface(winusb_handle, (UCHAR)(iface - 1),
+ &handle_priv->interface_handle[iface].api_handle)) {
+ handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
+ switch (GetLastError()) {
+ case ERROR_NO_MORE_ITEMS: // invalid iface
+ return LIBUSB_ERROR_NOT_FOUND;
+ case ERROR_BAD_COMMAND: // The device was disconnected
+ return LIBUSB_ERROR_NO_DEVICE;
+ case ERROR_ALREADY_EXISTS: // already claimed
+ return LIBUSB_ERROR_BUSY;
+ default:
+ usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0));
+ return LIBUSB_ERROR_ACCESS;
+ }
+ }
+ }
+ usbi_dbg("claimed interface %d", iface);
+ handle_priv->active_interface = iface;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
+{
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ HANDLE winusb_handle;
+
+ CHECK_WINUSBX_AVAILABLE(sub_api);
+
+ winusb_handle = handle_priv->interface_handle[iface].api_handle;
+ if (!HANDLE_VALID(winusb_handle))
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ WinUSBX[sub_api].Free(winusb_handle);
+ handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
+
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * Return the first valid interface (of the same API type), for control transfers
+ */
+static int get_valid_interface(struct libusb_device_handle *dev_handle, int api_id)
+{
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ int i;
+
+ if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) {
+ usbi_dbg("unsupported API ID");
+ return -1;
+ }
+
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if (HANDLE_VALID(handle_priv->interface_handle[i].dev_handle)
+ && HANDLE_VALID(handle_priv->interface_handle[i].api_handle)
+ && (priv->usb_interface[i].apib->id == api_id))
+ return i;
+ }
+
+ return -1;
+}
+
+/*
+ * Lookup interface by endpoint address. -1 if not found
+ */
+static int interface_by_endpoint(struct winusb_device_priv *priv,
+ struct winusb_device_handle_priv *handle_priv, uint8_t endpoint_address)
+{
+ int i, j;
+
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if (!HANDLE_VALID(handle_priv->interface_handle[i].api_handle))
+ continue;
+ if (priv->usb_interface[i].endpoint == NULL)
+ continue;
+ for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) {
+ if (priv->usb_interface[i].endpoint[j] == endpoint_address)
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
+ PWINUSB_SETUP_PACKET setup = (PWINUSB_SETUP_PACKET)transfer->buffer;
+ ULONG size;
+ HANDLE winusb_handle;
+ OVERLAPPED *overlapped;
+ int current_interface;
+
+ CHECK_WINUSBX_AVAILABLE(sub_api);
+
+ size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
+
+ // Windows places upper limits on the control transfer size
+ // See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff538112.aspx
+ if (size > MAX_CTRL_BUFFER_LENGTH)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ current_interface = get_valid_interface(transfer->dev_handle, USB_API_WINUSBX);
+ if (current_interface < 0) {
+ if (auto_claim(transfer, &current_interface, USB_API_WINUSBX) != LIBUSB_SUCCESS)
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ usbi_dbg("will use interface %d", current_interface);
+
+ transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
+ overlapped = transfer_priv->pollable_fd.overlapped;
+
+ // Sending of set configuration control requests from WinUSB creates issues
+ if ((LIBUSB_REQ_TYPE(setup->RequestType) == LIBUSB_REQUEST_TYPE_STANDARD)
+ && (setup->Request == LIBUSB_REQUEST_SET_CONFIGURATION)) {
+ if (setup->Value != priv->active_config) {
+ usbi_warn(ctx, "cannot set configuration other than the default one");
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+ windows_force_sync_completion(overlapped, 0);
+ } else {
+ if (!WinUSBX[sub_api].ControlTransfer(winusb_handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, overlapped)) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ usbi_warn(ctx, "ControlTransfer failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_IO;
+ }
+ } else {
+ windows_force_sync_completion(overlapped, size);
+ }
+ }
+
+ transfer_priv->interface_number = (uint8_t)current_interface;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ HANDLE winusb_handle;
+
+ CHECK_WINUSBX_AVAILABLE(sub_api);
+
+ if (altsetting > 255)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ winusb_handle = handle_priv->interface_handle[iface].api_handle;
+ if (!HANDLE_VALID(winusb_handle)) {
+ usbi_err(ctx, "interface must be claimed first");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ if (!WinUSBX[sub_api].SetCurrentAlternateSetting(winusb_handle, (UCHAR)altsetting)) {
+ usbi_err(ctx, "SetCurrentAlternateSetting failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_IO;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ HANDLE winusb_handle;
+ OVERLAPPED *overlapped;
+ bool ret;
+ int current_interface;
+ int i;
+ UINT offset;
+ PKISO_CONTEXT iso_context;
+ size_t iso_ctx_size;
+
+ CHECK_WINUSBX_AVAILABLE(sub_api);
+
+ if ((sub_api != SUB_API_LIBUSBK) && (sub_api != SUB_API_LIBUSB0)) {
+ // iso only supported on libusbk-based backends
+ PRINT_UNSUPPORTED_API(submit_iso_transfer);
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ };
+
+ current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
+
+ transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
+ overlapped = transfer_priv->pollable_fd.overlapped;
+
+ iso_ctx_size = sizeof(KISO_CONTEXT) + (transfer->num_iso_packets * sizeof(KISO_PACKET));
+ transfer_priv->iso_context = iso_context = calloc(1, iso_ctx_size);
+ if (transfer_priv->iso_context == NULL)
+ return LIBUSB_ERROR_NO_MEM;
+
+ // start ASAP
+ iso_context->StartFrame = 0;
+ iso_context->NumberOfPackets = (SHORT)transfer->num_iso_packets;
+
+ // convert the transfer packet lengths to iso_packet offsets
+ offset = 0;
+ for (i = 0; i < transfer->num_iso_packets; i++) {
+ iso_context->IsoPackets[i].offset = offset;
+ offset += transfer->iso_packet_desc[i].length;
+ }
+
+ if (IS_XFERIN(transfer)) {
+ usbi_dbg("reading %d iso packets", transfer->num_iso_packets);
+ ret = WinUSBX[sub_api].IsoReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context);
+ } else {
+ usbi_dbg("writing %d iso packets", transfer->num_iso_packets);
+ ret = WinUSBX[sub_api].IsoWritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context);
+ }
+
+ if (!ret) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ usbi_err(ctx, "IsoReadPipe/IsoWritePipe failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_IO;
+ }
+ } else {
+ windows_force_sync_completion(overlapped, (ULONG)transfer->length);
+ }
+
+ transfer_priv->interface_number = (uint8_t)current_interface;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ HANDLE winusb_handle;
+ OVERLAPPED *overlapped;
+ bool ret;
+ int current_interface;
+
+ CHECK_WINUSBX_AVAILABLE(sub_api);
+
+ current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
+
+ transfer_priv->handle = winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
+ overlapped = transfer_priv->pollable_fd.overlapped;
+
+ if (IS_XFERIN(transfer)) {
+ usbi_dbg("reading %d bytes", transfer->length);
+ ret = WinUSBX[sub_api].ReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped);
+ } else {
+ usbi_dbg("writing %d bytes", transfer->length);
+ ret = WinUSBX[sub_api].WritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped);
+ }
+
+ if (!ret) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_IO;
+ }
+ } else {
+ windows_force_sync_completion(overlapped, (ULONG)transfer->length);
+ }
+
+ transfer_priv->interface_number = (uint8_t)current_interface;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ HANDLE winusb_handle;
+ int current_interface;
+
+ CHECK_WINUSBX_AVAILABLE(sub_api);
+
+ current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface);
+ winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
+
+ if (!WinUSBX[sub_api].ResetPipe(winusb_handle, endpoint)) {
+ usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * from http://www.winvistatips.com/winusb-bugchecks-t335323.html (confirmed
+ * through testing as well):
+ * "You can not call WinUsb_AbortPipe on control pipe. You can possibly cancel
+ * the control transfer using CancelIo"
+ */
+static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer)
+{
+ // Cancelling of the I/O is done in the parent
+ return LIBUSB_SUCCESS;
+}
+
+static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ HANDLE handle;
+ int current_interface;
+
+ CHECK_WINUSBX_AVAILABLE(sub_api);
+
+ current_interface = transfer_priv->interface_number;
+ if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) {
+ usbi_err(ctx, "program assertion failed: invalid interface_number");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+ usbi_dbg("will use interface %d", current_interface);
+
+ if (WinUSBX[sub_api].CancelIoEx_supported) {
+ // Try to use CancelIoEx if available to cancel just a single transfer
+ handle = handle_priv->interface_handle[current_interface].dev_handle;
+ if (pCancelIoEx(handle, transfer_priv->pollable_fd.overlapped))
+ return LIBUSB_SUCCESS;
+ else if (GetLastError() == ERROR_NOT_FOUND)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ // Not every driver implements the necessary functionality for CancelIoEx
+ usbi_warn(ctx, "CancelIoEx not supported for sub API %s", winusbx_driver_names[sub_api]);
+ WinUSBX[sub_api].CancelIoEx_supported = false;
+ }
+
+ handle = handle_priv->interface_handle[current_interface].api_handle;
+ if (!WinUSBX[sub_api].AbortPipe(handle, transfer->endpoint)) {
+ usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * from the "How to Use WinUSB to Communicate with a USB Device" Microsoft white paper
+ * (http://www.microsoft.com/whdc/connect/usb/winusb_howto.mspx):
+ * "WinUSB does not support host-initiated reset port and cycle port operations" and
+ * IOCTL_INTERNAL_USB_CYCLE_PORT is only available in kernel mode and the
+ * IOCTL_USB_HUB_CYCLE_PORT ioctl was removed from Vista => the best we can do is
+ * cycle the pipes (and even then, the control pipe can not be reset using WinUSB)
+ */
+// TODO: (post hotplug): see if we can force eject the device and redetect it (reuse hotplug?)
+static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ HANDLE winusb_handle;
+ int i, j;
+
+ CHECK_WINUSBX_AVAILABLE(sub_api);
+
+ // Reset any available pipe (except control)
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ winusb_handle = handle_priv->interface_handle[i].api_handle;
+ if (HANDLE_VALID(winusb_handle)) {
+ for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) {
+ usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]);
+ if (!WinUSBX[sub_api].AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))
+ usbi_err(ctx, "AbortPipe (pipe address %02X) failed: %s",
+ priv->usb_interface[i].endpoint[j], windows_error_str(0));
+
+ // FlushPipe seems to fail on OUT pipes
+ if (IS_EPIN(priv->usb_interface[i].endpoint[j])
+ && (!WinUSBX[sub_api].FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j])))
+ usbi_err(ctx, "FlushPipe (pipe address %02X) failed: %s",
+ priv->usb_interface[i].endpoint[j], windows_error_str(0));
+
+ if (!WinUSBX[sub_api].ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))
+ usbi_err(ctx, "ResetPipe (pipe address %02X) failed: %s",
+ priv->usb_interface[i].endpoint[j], windows_error_str(0));
+ }
+ }
+ }
+
+ // libusbK & libusb0 have the ability to issue an actual device reset
+ if (WinUSBX[sub_api].ResetDevice != NULL) {
+ winusb_handle = handle_priv->interface_handle[0].api_handle;
+ if (HANDLE_VALID(winusb_handle))
+ WinUSBX[sub_api].ResetDevice(winusb_handle);
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ PKISO_CONTEXT iso_context;
+ int i;
+
+ if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
+ CHECK_WINUSBX_AVAILABLE(sub_api);
+
+ // for isochronous, need to copy the individual iso packet actual_lengths and statuses
+ if ((sub_api == SUB_API_LIBUSBK) || (sub_api == SUB_API_LIBUSB0)) {
+ // iso only supported on libusbk-based backends for now
+ iso_context = transfer_priv->iso_context;
+ for (i = 0; i < transfer->num_iso_packets; i++) {
+ transfer->iso_packet_desc[i].actual_length = iso_context->IsoPackets[i].actual_length;
+ // TODO translate USDB_STATUS codes http://msdn.microsoft.com/en-us/library/ff539136(VS.85).aspx to libusb_transfer_status
+ //transfer->iso_packet_desc[i].status = transfer_priv->iso_context->IsoPackets[i].status;
+ }
+ } else {
+ // This should only occur if backend is not set correctly or other backend isoc is partially implemented
+ PRINT_UNSUPPORTED_API(copy_transfer_data);
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ }
+ }
+
+ itransfer->transferred += io_size;
+ return LIBUSB_TRANSFER_COMPLETED;
+}
+
+/*
+ * Composite API functions
+ */
+static int composite_open(int sub_api, struct libusb_device_handle *dev_handle)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ int r = LIBUSB_ERROR_NOT_FOUND;
+ uint8_t i;
+ // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID
+ bool available[SUB_API_MAX + 1] = { 0 };
+
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ switch (priv->usb_interface[i].apib->id) {
+ case USB_API_WINUSBX:
+ if (priv->usb_interface[i].sub_api != SUB_API_NOTSET) {
+ available[priv->usb_interface[i].sub_api] = true;
+ }
+ break;
+ case USB_API_HID:
+ available[SUB_API_MAX] = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers
+ if (available[i]) {
+ r = usb_api_backend[USB_API_WINUSBX].open(i, dev_handle);
+ if (r != LIBUSB_SUCCESS) {
+ return r;
+ }
+ }
+ }
+/*
+ if (available[SUB_API_MAX]) // HID driver
+ r = hid_open(SUB_API_NOTSET, dev_handle);
+*/
+ return r;
+}
+
+static void composite_close(int sub_api, struct libusb_device_handle *dev_handle)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ uint8_t i;
+ // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID
+ bool available[SUB_API_MAX + 1] = { 0 };
+
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ switch (priv->usb_interface[i].apib->id) {
+ case USB_API_WINUSBX:
+ if (priv->usb_interface[i].sub_api != SUB_API_NOTSET)
+ available[priv->usb_interface[i].sub_api] = true;
+ break;
+ case USB_API_HID:
+ available[SUB_API_MAX] = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers
+ if (available[i])
+ usb_api_backend[USB_API_WINUSBX].close(i, dev_handle);
+ }
+/*
+ if (available[SUB_API_MAX]) // HID driver
+ hid_close(SUB_API_NOTSET, dev_handle);
+*/
+}
+
+static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+
+ CHECK_SUPPORTED_API(priv->usb_interface[iface].apib, claim_interface);
+
+ return priv->usb_interface[iface].apib->
+ claim_interface(priv->usb_interface[iface].sub_api, dev_handle, iface);
+}
+
+static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+
+ CHECK_SUPPORTED_API(priv->usb_interface[iface].apib, set_interface_altsetting);
+
+ return priv->usb_interface[iface].apib->
+ set_interface_altsetting(priv->usb_interface[iface].sub_api, dev_handle, iface, altsetting);
+}
+
+static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+
+ CHECK_SUPPORTED_API(priv->usb_interface[iface].apib, release_interface);
+
+ return priv->usb_interface[iface].apib->
+ release_interface(priv->usb_interface[iface].sub_api, dev_handle, iface);
+}
+
+static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ struct libusb_config_descriptor *conf_desc;
+ WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer;
+ int iface, pass, r;
+
+ // Interface shouldn't matter for control, but it does in practice, with Windows'
+ // restrictions with regards to accessing HID keyboards and mice. Try to target
+ // a specific interface first, if possible.
+ switch (LIBUSB_REQ_RECIPIENT(setup->RequestType)) {
+ case LIBUSB_RECIPIENT_INTERFACE:
+ iface = setup->Index & 0xFF;
+ break;
+ case LIBUSB_RECIPIENT_ENDPOINT:
+ r = libusb_get_active_config_descriptor(transfer->dev_handle->dev, &conf_desc);
+ if (r == LIBUSB_SUCCESS) {
+ iface = get_interface_by_endpoint(conf_desc, (setup->Index & 0xFF));
+ libusb_free_config_descriptor(conf_desc);
+ break;
+ }
+ // Fall through if not able to determine interface
+ default:
+ iface = -1;
+ break;
+ }
+
+ // Try and target a specific interface if the control setup indicates such
+ if ((iface >= 0) && (iface < USB_MAXINTERFACES)) {
+ usbi_dbg("attempting control transfer targeted to interface %d", iface);
+ if ((priv->usb_interface[iface].path != NULL)
+ && (priv->usb_interface[iface].apib->submit_control_transfer != NULL)) {
+ r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer);
+ if (r == LIBUSB_SUCCESS)
+ return r;
+ }
+ }
+
+ // Either not targeted to a specific interface or no luck in doing so.
+ // Try a 2 pass approach with all interfaces.
+ for (pass = 0; pass < 2; pass++) {
+ for (iface = 0; iface < USB_MAXINTERFACES; iface++) {
+ if ((priv->usb_interface[iface].path != NULL)
+ && (priv->usb_interface[iface].apib->submit_control_transfer != NULL)) {
+ if ((pass == 0) && (priv->usb_interface[iface].restricted_functionality)) {
+ usbi_dbg("trying to skip restricted interface #%d (HID keyboard or mouse?)", iface);
+ continue;
+ }
+ usbi_dbg("using interface %d", iface);
+ r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer);
+ // If not supported on this API, it may be supported on another, so don't give up yet!!
+ if (r == LIBUSB_ERROR_NOT_SUPPORTED)
+ continue;
+ return r;
+ }
+ }
+ }
+ usbi_err(ctx, "no libusb supported interfaces to complete request");
+ return LIBUSB_ERROR_NOT_FOUND;
+}
+
+static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ int current_interface;
+
+ current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, submit_bulk_transfer);
+
+ return priv->usb_interface[current_interface].apib->
+ submit_bulk_transfer(priv->usb_interface[current_interface].sub_api, itransfer);
+}
+
+static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ int current_interface;
+
+ current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, submit_iso_transfer);
+
+ return priv->usb_interface[current_interface].apib->
+ submit_iso_transfer(priv->usb_interface[current_interface].sub_api, itransfer);
+}
+
+static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct winusb_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ int current_interface;
+
+ current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, clear_halt);
+
+ return priv->usb_interface[current_interface].apib->
+ clear_halt(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint);
+}
+
+static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ int current_interface = transfer_priv->interface_number;
+
+ if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) {
+ usbi_err(TRANSFER_CTX(transfer), "program assertion failed: invalid interface_number");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, abort_control);
+
+ return priv->usb_interface[current_interface].apib->
+ abort_control(priv->usb_interface[current_interface].sub_api, itransfer);
+}
+
+static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ int current_interface = transfer_priv->interface_number;
+
+ if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) {
+ usbi_err(TRANSFER_CTX(transfer), "program assertion failed: invalid interface_number");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, abort_transfers);
+
+ return priv->usb_interface[current_interface].apib->
+ abort_transfers(priv->usb_interface[current_interface].sub_api, itransfer);
+}
+
+static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
+{
+ struct winusb_device_priv *priv = _device_priv(dev_handle->dev);
+ int r;
+ uint8_t i;
+ bool available[SUB_API_MAX];
+
+ for (i = 0; i < SUB_API_MAX; i++)
+ available[i] = false;
+
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if ((priv->usb_interface[i].apib->id == USB_API_WINUSBX)
+ && (priv->usb_interface[i].sub_api != SUB_API_NOTSET))
+ available[priv->usb_interface[i].sub_api] = true;
+ }
+
+ for (i = 0; i < SUB_API_MAX; i++) {
+ if (available[i]) {
+ r = usb_api_backend[USB_API_WINUSBX].reset_device(i, dev_handle);
+ if (r != LIBUSB_SUCCESS)
+ return r;
+ }
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size)
+{
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct winusb_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct winusb_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+ int current_interface = transfer_priv->interface_number;
+
+ CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, copy_transfer_data);
+
+ return priv->usb_interface[current_interface].apib->
+ copy_transfer_data(priv->usb_interface[current_interface].sub_api, itransfer, io_size);
+}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.h b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.h
index b7b9cd919..c1ad4eb9b 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/os/windows_winusb.h
@@ -36,15 +36,14 @@
#endif
// Missing from MSVC6 setupapi.h
-#if !defined(SPDRP_ADDRESS)
+#ifndef SPDRP_ADDRESS
#define SPDRP_ADDRESS 28
#endif
-#if !defined(SPDRP_INSTALL_STATE)
+#ifndef SPDRP_INSTALL_STATE
#define SPDRP_INSTALL_STATE 34
#endif
#define MAX_CTRL_BUFFER_LENGTH 4096
-#define MAX_USB_DEVICES 256
#define MAX_USB_STRING_LENGTH 128
#define MAX_HID_REPORT_SIZE 1024
#define MAX_HID_DESCRIPTOR_SIZE 256
@@ -61,17 +60,17 @@
// http://msdn.microsoft.com/en-us/library/ff545978.aspx
// http://msdn.microsoft.com/en-us/library/ff545972.aspx
// http://msdn.microsoft.com/en-us/library/ff545982.aspx
-#if !defined(GUID_DEVINTERFACE_USB_HOST_CONTROLLER)
-const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27} };
+#ifndef GUID_DEVINTERFACE_USB_HOST_CONTROLLER
+const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = {0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27}};
#endif
-#if !defined(GUID_DEVINTERFACE_USB_DEVICE)
-const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED} };
+#ifndef GUID_DEVINTERFACE_USB_DEVICE
+const GUID GUID_DEVINTERFACE_USB_DEVICE = {0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}};
#endif
-#if !defined(GUID_DEVINTERFACE_USB_HUB)
-const GUID GUID_DEVINTERFACE_USB_HUB = { 0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8} };
+#ifndef GUID_DEVINTERFACE_USB_HUB
+const GUID GUID_DEVINTERFACE_USB_HUB = {0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8}};
#endif
-#if !defined(GUID_DEVINTERFACE_LIBUSB0_FILTER)
-const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9} };
+#ifndef GUID_DEVINTERFACE_LIBUSB0_FILTER
+const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = {0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9}};
#endif
@@ -84,8 +83,6 @@ const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8
#define USB_API_WINUSBX 3
#define USB_API_HID 4
#define USB_API_MAX 5
-// The following is used to indicate if the HID or composite extra props have already been set.
-#define USB_API_SET (1 << USB_API_MAX)
// Sub-APIs for WinUSB-like driver APIs (WinUSB, libusbK, libusb-win32 through the libusbK DLL)
// Must have the same values as the KUSB_DRVID enum from libusbk.h
@@ -95,15 +92,13 @@ const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8
#define SUB_API_WINUSB 2
#define SUB_API_MAX 3
-#define WINUSBX_DRV_NAMES {"libusbK", "libusb0", "WinUSB"}
-
struct windows_usb_api_backend {
const uint8_t id;
- const char *designation;
- const char **driver_name_list; // Driver name, without .sys, e.g. "usbccgp"
+ const char * const designation;
+ const char * const * const driver_name_list; // Driver name, without .sys, e.g. "usbccgp"
const uint8_t nb_driver_names;
- int (*init)(int sub_api, struct libusb_context *ctx);
- int (*exit)(int sub_api);
+ int (*init)(struct libusb_context *ctx);
+ void (*exit)(void);
int (*open)(int sub_api, struct libusb_device_handle *dev_handle);
void (*close)(int sub_api, struct libusb_device_handle *dev_handle);
int (*configure_endpoints)(int sub_api, struct libusb_device_handle *dev_handle, int iface);
@@ -123,9 +118,16 @@ struct windows_usb_api_backend {
extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX];
#define PRINT_UNSUPPORTED_API(fname) \
- usbi_dbg("unsupported API call for '" \
- #fname "' (unrecognized device driver)"); \
- return LIBUSB_ERROR_NOT_SUPPORTED;
+ usbi_dbg("unsupported API call for '%s' " \
+ "(unrecognized device driver)", #fname)
+
+#define CHECK_SUPPORTED_API(apip, fname) \
+ do { \
+ if ((apip)->fname == NULL) { \
+ PRINT_UNSUPPORTED_API(fname); \
+ return LIBUSB_ERROR_NOT_SUPPORTED; \
+ } \
+ } while (0)
/*
* private structures definition
@@ -154,15 +156,16 @@ struct libusb_hid_descriptor {
#define LIBUSB_REQ_IN(request_type) ((request_type) & LIBUSB_ENDPOINT_IN)
#define LIBUSB_REQ_OUT(request_type) (!LIBUSB_REQ_IN(request_type))
+#ifndef CTL_CODE
+#define CTL_CODE(DeviceType, Function, Method, Access) \
+ (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
+#endif
+
// The following are used for HID reports IOCTLs
-#define HID_CTL_CODE(id) \
- CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_NEITHER, FILE_ANY_ACCESS)
-#define HID_BUFFER_CTL_CODE(id) \
- CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HID_IN_CTL_CODE(id) \
- CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define HID_OUT_CTL_CODE(id) \
- CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100)
#define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104)
@@ -193,39 +196,20 @@ struct hid_device_priv {
uint16_t input_report_size;
uint16_t output_report_size;
uint16_t feature_report_size;
+ uint16_t usage;
+ uint16_t usagePage;
WCHAR string[3][MAX_USB_STRING_LENGTH];
uint8_t string_index[3]; // man, prod, ser
};
-struct windows_device_priv {
- uint8_t depth; // distance to HCD
- uint8_t port; // port number on the hub
- uint8_t active_config;
- struct windows_usb_api_backend const *apib;
- char *path; // device interface path
- int sub_api; // for WinUSB-like APIs
- struct {
- char *path; // each interface needs a device interface path,
- struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support),
- int sub_api;
- int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
- uint8_t *endpoint;
- bool restricted_functionality; // indicates if the interface functionality is restricted
- // by Windows (eg. HID keyboards or mice cannot do R/W)
- } usb_interface[USB_MAXINTERFACES];
- struct hid_device_priv *hid;
- USB_DEVICE_DESCRIPTOR dev_descriptor;
- unsigned char **config_descriptor; // list of pointers to the cached config descriptors
-};
-
-static inline struct windows_device_priv *_device_priv(struct libusb_device *dev)
+static inline struct winusb_device_priv *_device_priv(struct libusb_device *dev)
{
- return (struct windows_device_priv *)dev->os_priv;
+ return (struct winusb_device_priv *)dev->os_priv;
}
-static inline struct windows_device_priv *windows_device_priv_init(struct libusb_device *dev)
+static inline struct winusb_device_priv *winusb_device_priv_init(struct libusb_device *dev)
{
- struct windows_device_priv *p = _device_priv(dev);
+ struct winusb_device_priv *p = _device_priv(dev);
int i;
p->apib = &usb_api_backend[USB_API_UNSUPPORTED];
@@ -238,11 +222,12 @@ static inline struct windows_device_priv *windows_device_priv_init(struct libusb
return p;
}
-static inline void windows_device_priv_release(struct libusb_device *dev)
+static inline void winusb_device_priv_release(struct libusb_device *dev)
{
- struct windows_device_priv *p = _device_priv(dev);
+ struct winusb_device_priv *p = _device_priv(dev);
int i;
+ free(p->dev_id);
free(p->path);
if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) {
for (i = 0; i < dev->num_configurations; i++)
@@ -256,32 +241,12 @@ static inline void windows_device_priv_release(struct libusb_device *dev)
}
}
-struct interface_handle_t {
- HANDLE dev_handle; // WinUSB needs an extra handle for the file
- HANDLE api_handle; // used by the API to communicate with the device
-};
-
-struct windows_device_handle_priv {
- int active_interface;
- struct interface_handle_t interface_handle[USB_MAXINTERFACES];
- int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
-};
-
-static inline struct windows_device_handle_priv *_device_handle_priv(
+static inline struct winusb_device_handle_priv *_device_handle_priv(
struct libusb_device_handle *handle)
{
- return (struct windows_device_handle_priv *)handle->os_priv;
+ return (struct winusb_device_handle_priv *)handle->os_priv;
}
-// used for async polling functions
-struct windows_transfer_priv {
- struct winfd pollable_fd;
- uint8_t interface_number;
- uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID
- uint8_t *hid_dest; // transfer buffer destination, required for HID
- size_t hid_expected_size;
-};
-
// used to match a device driver (including filter drivers) against a supported API
struct driver_lookup {
char list[MAX_KEY_LENGTH + 1]; // REG_MULTI_SZ list of services (driver) names
@@ -289,94 +254,72 @@ struct driver_lookup {
const char* designation; // internal designation (for debug output)
};
+/*
+ * Windows DDK API definitions. Most of it copied from MinGW's includes
+ */
+typedef DWORD DEVNODE, DEVINST;
+typedef DEVNODE *PDEVNODE, *PDEVINST;
+typedef DWORD RETURN_TYPE;
+typedef RETURN_TYPE CONFIGRET;
+
+#define CR_SUCCESS 0x00000000
+
+/* Cfgmgr32 dependencies */
+DLL_DECLARE_HANDLE(Cfgmgr32);
+DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG));
+DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG));
+
+/* AdvAPI32 dependencies */
+DLL_DECLARE_HANDLE(AdvAPI32);
+DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
+DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY));
+
/* OLE32 dependency */
DLL_DECLARE_HANDLE(OLE32);
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID));
-
-/* Kernel32 dependencies */
-DLL_DECLARE_HANDLE(Kernel32);
-/* This call is only available from XP SP2 */
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, IsWow64Process, (HANDLE, PBOOL));
+DLL_DECLARE_FUNC_PREFIXED(WINAPI, HRESULT, p, IIDFromString, (LPCOLESTR, LPIID));
/* SetupAPI dependencies */
DLL_DECLARE_HANDLE(SetupAPI);
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (const GUID*, PCSTR, HWND, DWORD));
+DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (LPCGUID, PCSTR, HWND, DWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA,
- const GUID*, DWORD, PSP_DEVICE_INTERFACE_DATA));
+ LPCGUID, DWORD, PSP_DEVICE_INTERFACE_DATA));
+DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInstanceIdA, (HDEVINFO, PSP_DEVINFO_DATA,
+ PCSTR, DWORD, PDWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA,
PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO,
PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD));
+DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO));
+DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, DWORD));
-/* AdvAPI32 dependencies */
-DLL_DECLARE_HANDLE(AdvAPI32);
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY));
-/*
- * Windows DDK API definitions. Most of it copied from MinGW's includes
- */
-typedef DWORD DEVNODE, DEVINST;
-typedef DEVNODE *PDEVNODE, *PDEVINST;
-typedef DWORD RETURN_TYPE;
-typedef RETURN_TYPE CONFIGRET;
-
-#define CR_SUCCESS 0x00000000
-#define CR_NO_SUCH_DEVNODE 0x0000000D
-
-#define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE
-#define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG
-#define USB_STRING_DESCRIPTOR_TYPE LIBUSB_DT_STRING
-#define USB_INTERFACE_DESCRIPTOR_TYPE LIBUSB_DT_INTERFACE
-#define USB_ENDPOINT_DESCRIPTOR_TYPE LIBUSB_DT_ENDPOINT
-
-#define USB_REQUEST_GET_STATUS LIBUSB_REQUEST_GET_STATUS
-#define USB_REQUEST_CLEAR_FEATURE LIBUSB_REQUEST_CLEAR_FEATURE
-#define USB_REQUEST_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE
-#define USB_REQUEST_SET_ADDRESS LIBUSB_REQUEST_SET_ADDRESS
-#define USB_REQUEST_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR
-#define USB_REQUEST_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR
-#define USB_REQUEST_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION
-#define USB_REQUEST_SET_CONFIGURATION LIBUSB_REQUEST_SET_CONFIGURATION
-#define USB_REQUEST_GET_INTERFACE LIBUSB_REQUEST_GET_INTERFACE
-#define USB_REQUEST_SET_INTERFACE LIBUSB_REQUEST_SET_INTERFACE
-#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME
-
-#define USB_GET_NODE_INFORMATION 258
-#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260
-#define USB_GET_NODE_CONNECTION_NAME 261
-#define USB_GET_HUB_CAPABILITIES 271
-#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX)
-#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274
+#ifndef USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION
+#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260
#endif
-#if !defined(USB_GET_HUB_CAPABILITIES_EX)
-#define USB_GET_HUB_CAPABILITIES_EX 276
+#ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX
+#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274
#endif
-#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX_V2)
+#ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX_V2
#define USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 279
#endif
-#ifndef METHOD_BUFFERED
-#define METHOD_BUFFERED 0
-#endif
-#ifndef FILE_ANY_ACCESS
-#define FILE_ANY_ACCESS 0x00000000
-#endif
-#ifndef FILE_DEVICE_UNKNOWN
-#define FILE_DEVICE_UNKNOWN 0x00000022
-#endif
#ifndef FILE_DEVICE_USB
-#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN
+#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN
#endif
-#ifndef CTL_CODE
-#define CTL_CODE(DeviceType, Function, Method, Access) \
- (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
-#endif
+#define USB_CTL_CODE(id) \
+ CTL_CODE(FILE_DEVICE_USB, (id), METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \
+ USB_CTL_CODE(USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION)
+
+#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \
+ USB_CTL_CODE(USB_GET_NODE_CONNECTION_INFORMATION_EX)
+
+#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \
+ USB_CTL_CODE(USB_GET_NODE_CONNECTION_INFORMATION_EX_V2)
typedef enum USB_CONNECTION_STATUS {
NoDeviceConnected,
@@ -395,79 +338,10 @@ typedef enum USB_HUB_NODE {
UsbMIParent
} USB_HUB_NODE;
-/* Cfgmgr32.dll interface */
-DLL_DECLARE_HANDLE(Cfgmgr32);
-DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG));
-DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG));
-DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG));
-DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG));
-
-#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \
- CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#define IOCTL_USB_GET_HUB_CAPABILITIES \
- CTL_CODE(FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \
- CTL_CODE(FILE_DEVICE_USB, USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#define IOCTL_USB_GET_ROOT_HUB_NAME \
- CTL_CODE(FILE_DEVICE_USB, HCD_GET_ROOT_HUB_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#define IOCTL_USB_GET_NODE_INFORMATION \
- CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \
- CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \
- CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#define IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES \
- CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_ATTRIBUTES, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#define IOCTL_USB_GET_NODE_CONNECTION_NAME \
- CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
// Most of the structures below need to be packed
-#pragma pack(push, 1)
-
-typedef struct USB_INTERFACE_DESCRIPTOR {
- UCHAR bLength;
- UCHAR bDescriptorType;
- UCHAR bInterfaceNumber;
- UCHAR bAlternateSetting;
- UCHAR bNumEndpoints;
- UCHAR bInterfaceClass;
- UCHAR bInterfaceSubClass;
- UCHAR bInterfaceProtocol;
- UCHAR iInterface;
-} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR;
-
-typedef struct USB_CONFIGURATION_DESCRIPTOR_SHORT {
- struct {
- ULONG ConnectionIndex;
- struct {
- UCHAR bmRequest;
- UCHAR bRequest;
- USHORT wValue;
- USHORT wIndex;
- USHORT wLength;
- } SetupPacket;
- } req;
- USB_CONFIGURATION_DESCRIPTOR data;
-} USB_CONFIGURATION_DESCRIPTOR_SHORT;
-
-typedef struct USB_ENDPOINT_DESCRIPTOR {
- UCHAR bLength;
- UCHAR bDescriptorType;
- UCHAR bEndpointAddress;
- UCHAR bmAttributes;
- USHORT wMaxPacketSize;
- UCHAR bInterval;
-} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR;
+#include <pshpack1.h>
-typedef struct USB_DESCRIPTOR_REQUEST {
+typedef struct _USB_DESCRIPTOR_REQUEST {
ULONG ConnectionIndex;
struct {
UCHAR bmRequest;
@@ -479,68 +353,24 @@ typedef struct USB_DESCRIPTOR_REQUEST {
// UCHAR Data[0];
} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST;
-typedef struct USB_HUB_DESCRIPTOR {
- UCHAR bDescriptorLength;
- UCHAR bDescriptorType;
- UCHAR bNumberOfPorts;
- USHORT wHubCharacteristics;
- UCHAR bPowerOnToPowerGood;
- UCHAR bHubControlCurrent;
- UCHAR bRemoveAndPowerMask[64];
-} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR;
-
-typedef struct USB_ROOT_HUB_NAME {
- ULONG ActualLength;
- WCHAR RootHubName[1];
-} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME;
-
-typedef struct USB_ROOT_HUB_NAME_FIXED {
- ULONG ActualLength;
- WCHAR RootHubName[MAX_PATH_LENGTH];
-} USB_ROOT_HUB_NAME_FIXED;
-
-typedef struct USB_NODE_CONNECTION_NAME {
- ULONG ConnectionIndex;
- ULONG ActualLength;
- WCHAR NodeName[1];
-} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME;
-
-typedef struct USB_NODE_CONNECTION_NAME_FIXED {
- ULONG ConnectionIndex;
- ULONG ActualLength;
- WCHAR NodeName[MAX_PATH_LENGTH];
-} USB_NODE_CONNECTION_NAME_FIXED;
-
-typedef struct USB_HUB_NAME_FIXED {
- union {
- USB_ROOT_HUB_NAME_FIXED root;
- USB_NODE_CONNECTION_NAME_FIXED node;
- } u;
-} USB_HUB_NAME_FIXED;
-
-typedef struct USB_HUB_INFORMATION {
- USB_HUB_DESCRIPTOR HubDescriptor;
- BOOLEAN HubIsBusPowered;
-} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION;
-
-typedef struct USB_MI_PARENT_INFORMATION {
- ULONG NumberOfInterfaces;
-} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION;
-
-typedef struct USB_NODE_INFORMATION {
- USB_HUB_NODE NodeType;
- union {
- USB_HUB_INFORMATION HubInformation;
- USB_MI_PARENT_INFORMATION MiParentInformation;
- } u;
-} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION;
+typedef struct _USB_CONFIGURATION_DESCRIPTOR_SHORT {
+ USB_DESCRIPTOR_REQUEST req;
+ USB_CONFIGURATION_DESCRIPTOR desc;
+} USB_CONFIGURATION_DESCRIPTOR_SHORT;
-typedef struct USB_PIPE_INFO {
- USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
- ULONG ScheduleOffset;
-} USB_PIPE_INFO, *PUSB_PIPE_INFO;
+typedef struct USB_INTERFACE_DESCRIPTOR {
+ UCHAR bLength;
+ UCHAR bDescriptorType;
+ UCHAR bInterfaceNumber;
+ UCHAR bAlternateSetting;
+ UCHAR bNumEndpoints;
+ UCHAR bInterfaceClass;
+ UCHAR bInterfaceSubClass;
+ UCHAR bInterfaceProtocol;
+ UCHAR iInterface;
+} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR;
-typedef struct USB_NODE_CONNECTION_INFORMATION_EX {
+typedef struct _USB_NODE_CONNECTION_INFORMATION_EX {
ULONG ConnectionIndex;
USB_DEVICE_DESCRIPTOR DeviceDescriptor;
UCHAR CurrentConfigurationValue;
@@ -578,25 +408,7 @@ typedef struct _USB_NODE_CONNECTION_INFORMATION_EX_V2 {
USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS Flags;
} USB_NODE_CONNECTION_INFORMATION_EX_V2, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2;
-typedef struct USB_HUB_CAP_FLAGS {
- ULONG HubIsHighSpeedCapable:1;
- ULONG HubIsHighSpeed:1;
- ULONG HubIsMultiTtCapable:1;
- ULONG HubIsMultiTt:1;
- ULONG HubIsRoot:1;
- ULONG HubIsArmedWakeOnConnect:1;
- ULONG ReservedMBZ:26;
-} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS;
-
-typedef struct USB_HUB_CAPABILITIES {
- ULONG HubIs2xCapable:1;
-} USB_HUB_CAPABILITIES, *PUSB_HUB_CAPABILITIES;
-
-typedef struct USB_HUB_CAPABILITIES_EX {
- USB_HUB_CAP_FLAGS CapabilityFlags;
-} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX;
-
-#pragma pack(pop)
+#include <poppack.h>
/* winusb.dll interface */
@@ -608,36 +420,25 @@ typedef struct USB_HUB_CAPABILITIES_EX {
#define AUTO_FLUSH 0x06
#define RAW_IO 0x07
#define MAXIMUM_TRANSFER_SIZE 0x08
-#define AUTO_SUSPEND 0x81
-#define SUSPEND_DELAY 0x83
-#define DEVICE_SPEED 0x01
-#define LowSpeed 0x01
-#define FullSpeed 0x02
-#define HighSpeed 0x03
-
-typedef enum USBD_PIPE_TYPE {
+
+typedef enum _USBD_PIPE_TYPE {
UsbdPipeTypeControl,
UsbdPipeTypeIsochronous,
UsbdPipeTypeBulk,
UsbdPipeTypeInterrupt
} USBD_PIPE_TYPE;
-typedef struct {
- USBD_PIPE_TYPE PipeType;
- UCHAR PipeId;
- USHORT MaximumPacketSize;
- UCHAR Interval;
-} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION;
-
-#pragma pack(1)
-typedef struct {
- UCHAR request_type;
- UCHAR request;
- USHORT value;
- USHORT index;
- USHORT length;
+#include <pshpack1.h>
+
+typedef struct _WINUSB_SETUP_PACKET {
+ UCHAR RequestType;
+ UCHAR Request;
+ USHORT Value;
+ USHORT Index;
+ USHORT Length;
} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET;
-#pragma pack()
+
+#include <poppack.h>
typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
@@ -665,59 +466,10 @@ typedef BOOL (WINAPI *WinUsb_GetAssociatedInterface_t)(
UCHAR AssociatedInterfaceIndex,
PWINUSB_INTERFACE_HANDLE AssociatedInterfaceHandle
);
-typedef BOOL (WINAPI *WinUsb_GetCurrentAlternateSetting_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- PUCHAR AlternateSetting
-);
-typedef BOOL (WINAPI *WinUsb_GetDescriptor_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR DescriptorType,
- UCHAR Index,
- USHORT LanguageID,
- PUCHAR Buffer,
- ULONG BufferLength,
- PULONG LengthTransferred
-);
-typedef BOOL (WINAPI *WinUsb_GetOverlappedResult_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- LPOVERLAPPED lpOverlapped,
- LPDWORD lpNumberOfBytesTransferred,
- BOOL bWait
-);
-typedef BOOL (WINAPI *WinUsb_GetPipePolicy_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID,
- ULONG PolicyType,
- PULONG ValueLength,
- PVOID Value
-);
-typedef BOOL (WINAPI *WinUsb_GetPowerPolicy_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- ULONG PolicyType,
- PULONG ValueLength,
- PVOID Value
-);
typedef BOOL (WINAPI *WinUsb_Initialize_t)(
HANDLE DeviceHandle,
PWINUSB_INTERFACE_HANDLE InterfaceHandle
);
-typedef BOOL (WINAPI *WinUsb_QueryDeviceInformation_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- ULONG InformationType,
- PULONG BufferLength,
- PVOID Buffer
-);
-typedef BOOL (WINAPI *WinUsb_QueryInterfaceSettings_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR AlternateSettingNumber,
- PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor
-);
-typedef BOOL (WINAPI *WinUsb_QueryPipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR AlternateInterfaceNumber,
- UCHAR PipeIndex,
- PWINUSB_PIPE_INFORMATION PipeInformation
-);
typedef BOOL (WINAPI *WinUsb_ReadPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
@@ -726,6 +478,9 @@ typedef BOOL (WINAPI *WinUsb_ReadPipe_t)(
PULONG LengthTransferred,
LPOVERLAPPED Overlapped
);
+typedef BOOL (WINAPI *WinUsb_ResetDevice_t)(
+ WINUSB_INTERFACE_HANDLE InterfaceHandle
+);
typedef BOOL (WINAPI *WinUsb_ResetPipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID
@@ -741,12 +496,6 @@ typedef BOOL (WINAPI *WinUsb_SetPipePolicy_t)(
ULONG ValueLength,
PVOID Value
);
-typedef BOOL (WINAPI *WinUsb_SetPowerPolicy_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- ULONG PolicyType,
- ULONG ValueLength,
- PVOID Value
-);
typedef BOOL (WINAPI *WinUsb_WritePipe_t)(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
@@ -755,9 +504,6 @@ typedef BOOL (WINAPI *WinUsb_WritePipe_t)(
PULONG LengthTransferred,
LPOVERLAPPED Overlapped
);
-typedef BOOL (WINAPI *WinUsb_ResetDevice_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle
-);
/* /!\ These must match the ones from the official libusbk.h */
typedef enum _KUSB_FNID {
@@ -803,8 +549,7 @@ typedef struct _KLIB_VERSION {
INT Minor;
INT Micro;
INT Nano;
-} KLIB_VERSION;
-typedef KLIB_VERSION* PKLIB_VERSION;
+} KLIB_VERSION, *PKLIB_VERSION;
typedef BOOL (WINAPI *LibK_GetProcAddress_t)(
PVOID *ProcAddress,
@@ -816,29 +561,63 @@ typedef VOID (WINAPI *LibK_GetVersion_t)(
PKLIB_VERSION Version
);
+//KISO_PACKET is equivalent of libusb_iso_packet_descriptor except uses absolute "offset" field instead of sequential Lengths
+typedef struct _KISO_PACKET {
+ UINT offset;
+ USHORT actual_length; //changed from libusbk_shared.h "Length" for clarity
+ USHORT status;
+} KISO_PACKET, *PKISO_PACKET;
+
+typedef enum _KISO_FLAG {
+ KISO_FLAG_NONE = 0,
+ KISO_FLAG_SET_START_FRAME = 0x00000001,
+} KISO_FLAG;
+
+//KISO_CONTEXT is the conceptual equivalent of libusb_transfer except is isochronous-specific and must match libusbk's version
+typedef struct _KISO_CONTEXT {
+ KISO_FLAG Flags;
+ UINT StartFrame;
+ SHORT ErrorCount;
+ SHORT NumberOfPackets;
+ UINT UrbHdrStatus;
+ KISO_PACKET IsoPackets[0];
+} KISO_CONTEXT, *PKISO_CONTEXT;
+
+typedef BOOL(WINAPI *WinUsb_IsoReadPipe_t)(
+ WINUSB_INTERFACE_HANDLE InterfaceHandle,
+ UCHAR PipeID,
+ PUCHAR Buffer,
+ ULONG BufferLength,
+ LPOVERLAPPED Overlapped,
+ PKISO_CONTEXT IsoContext
+);
+
+typedef BOOL(WINAPI *WinUsb_IsoWritePipe_t)(
+ WINUSB_INTERFACE_HANDLE InterfaceHandle,
+ UCHAR PipeID,
+ PUCHAR Buffer,
+ ULONG BufferLength,
+ LPOVERLAPPED Overlapped,
+ PKISO_CONTEXT IsoContext
+);
+
struct winusb_interface {
bool initialized;
+ bool CancelIoEx_supported;
WinUsb_AbortPipe_t AbortPipe;
WinUsb_ControlTransfer_t ControlTransfer;
WinUsb_FlushPipe_t FlushPipe;
WinUsb_Free_t Free;
WinUsb_GetAssociatedInterface_t GetAssociatedInterface;
- WinUsb_GetCurrentAlternateSetting_t GetCurrentAlternateSetting;
- WinUsb_GetDescriptor_t GetDescriptor;
- WinUsb_GetOverlappedResult_t GetOverlappedResult;
- WinUsb_GetPipePolicy_t GetPipePolicy;
- WinUsb_GetPowerPolicy_t GetPowerPolicy;
WinUsb_Initialize_t Initialize;
- WinUsb_QueryDeviceInformation_t QueryDeviceInformation;
- WinUsb_QueryInterfaceSettings_t QueryInterfaceSettings;
- WinUsb_QueryPipe_t QueryPipe;
WinUsb_ReadPipe_t ReadPipe;
+ WinUsb_ResetDevice_t ResetDevice;
WinUsb_ResetPipe_t ResetPipe;
WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting;
WinUsb_SetPipePolicy_t SetPipePolicy;
- WinUsb_SetPowerPolicy_t SetPowerPolicy;
WinUsb_WritePipe_t WritePipe;
- WinUsb_ResetDevice_t ResetDevice;
+ WinUsb_IsoReadPipe_t IsoReadPipe;
+ WinUsb_IsoWritePipe_t IsoWritePipe;
};
/* hid.dll interface */
@@ -846,34 +625,10 @@ struct winusb_interface {
#define HIDP_STATUS_SUCCESS 0x110000
typedef void * PHIDP_PREPARSED_DATA;
-#pragma pack(1)
-typedef struct {
- ULONG Size;
- USHORT VendorID;
- USHORT ProductID;
- USHORT VersionNumber;
-} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
-#pragma pack()
+#include <pshpack1.h>
+#include <poppack.h>
typedef USHORT USAGE;
-typedef struct {
- USAGE Usage;
- USAGE UsagePage;
- USHORT InputReportByteLength;
- USHORT OutputReportByteLength;
- USHORT FeatureReportByteLength;
- USHORT Reserved[17];
- USHORT NumberLinkCollectionNodes;
- USHORT NumberInputButtonCaps;
- USHORT NumberInputValueCaps;
- USHORT NumberInputDataIndices;
- USHORT NumberOutputButtonCaps;
- USHORT NumberOutputValueCaps;
- USHORT NumberOutputDataIndices;
- USHORT NumberFeatureButtonCaps;
- USHORT NumberFeatureValueCaps;
- USHORT NumberFeatureDataIndices;
-} HIDP_CAPS, *PHIDP_CAPS;
typedef enum _HIDP_REPORT_TYPE {
HidP_Input,
@@ -919,19 +674,7 @@ typedef struct _HIDP_VALUE_CAPS {
} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS;
DLL_DECLARE_HANDLE(hid);
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES));
DLL_DECLARE_FUNC(WINAPI, VOID, HidD_GetHidGuid, (LPGUID));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPreparsedData, (HANDLE, PHIDP_PREPARSED_DATA *));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FreePreparsedData, (PHIDP_PREPARSED_DATA));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetManufacturerString, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetProductString, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetSerialNumberString, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, LONG, HidP_GetCaps, (PHIDP_PREPARSED_DATA, PHIDP_CAPS));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetNumInputBuffers, (HANDLE, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetFeature, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetFeature, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetInputReport, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetOutputReport, (HANDLE, PVOID, ULONG));
DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FlushQueue, (HANDLE));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA)); \ No newline at end of file
+DLL_DECLARE_FUNC(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA));
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/strerror.c b/vendor/github.com/karalabe/usb/libusb/libusb/strerror.c
index d2be0e2a0..d2be0e2a0 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/strerror.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/strerror.c
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/sync.c b/vendor/github.com/karalabe/usb/libusb/libusb/sync.c
index a609f65f4..a609f65f4 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/sync.c
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/sync.c
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/version.h b/vendor/github.com/karalabe/usb/libusb/libusb/version.h
index 6ce48a7d0..c6dfe3709 100644
--- a/vendor/github.com/karalabe/hid/libusb/libusb/version.h
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/version.h
@@ -7,7 +7,7 @@
#define LIBUSB_MINOR 0
#endif
#ifndef LIBUSB_MICRO
-#define LIBUSB_MICRO 21
+#define LIBUSB_MICRO 22
#endif
#ifndef LIBUSB_NANO
#define LIBUSB_NANO 0
diff --git a/vendor/github.com/karalabe/usb/libusb/libusb/version_nano.h b/vendor/github.com/karalabe/usb/libusb/libusb/version_nano.h
new file mode 100644
index 000000000..90a782a6b
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/libusb/libusb/version_nano.h
@@ -0,0 +1 @@
+#define LIBUSB_NANO 11312
diff --git a/vendor/github.com/karalabe/usb/raw_disabled.go b/vendor/github.com/karalabe/usb/raw_disabled.go
new file mode 100644
index 000000000..a05ef8ebb
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/raw_disabled.go
@@ -0,0 +1,42 @@
+// usb - Self contained USB and HID library for Go
+// Copyright 2017 The library Authors
+//
+// This library is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// The library is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License along
+// with the library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build !freebsd,!linux,!darwin,!windows ios !cgo
+
+package usb
+
+// RawDevice is a live raw USB connected device handle. On platforms that this file
+// implements, the type lacks the actual USB device and all methods are noop.
+type RawDevice struct {
+ DeviceInfo // Embed the infos for easier access
+}
+
+// Close releases the USB device handle. On platforms that this file implements,
+// the method is just a noop.
+func (dev *RawDevice) Close() error {
+ return ErrUnsupportedPlatform
+}
+
+// Write sends a binary blob to a USB device. On platforms that this file
+// implements, the method just returns an error.
+func (dev *RawDevice) Write(b []byte) (int, error) {
+ return 0, ErrUnsupportedPlatform
+}
+
+// Read retrieves a binary blob from a USB device. On platforms that this file
+// implements, the method just returns an error.
+func (dev *RawDevice) Read(b []byte) (int, error) {
+ return 0, ErrUnsupportedPlatform
+}
diff --git a/vendor/github.com/karalabe/usb/raw_enabled.go b/vendor/github.com/karalabe/usb/raw_enabled.go
new file mode 100644
index 000000000..326ac97ad
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/raw_enabled.go
@@ -0,0 +1,253 @@
+// usb - Self contained USB and HID library for Go
+// Copyright 2019 The library Authors
+//
+// This library is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// The library is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License along
+// with the library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build freebsd,cgo linux,cgo darwin,!ios,cgo windows,cgo
+
+package usb
+
+/*
+ #include "./libusb/libusb/libusb.h"
+
+ // ctx is a global libusb context to interact with devices through.
+ libusb_context* ctx;
+*/
+import "C"
+
+import (
+ "fmt"
+ "reflect"
+ "sync"
+ "unsafe"
+)
+
+// enumerateRaw returns a list of all the USB 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 USB devices are returned.
+func enumerateRaw(vendorID uint16, productID uint16) ([]DeviceInfo, error) {
+ // Enumerate the devices, and free all the matching refcounts (we'll reopen any
+ // explicitly requested).
+ infos, err := enumerateRawWithRef(vendorID, productID)
+ for _, info := range infos {
+ C.libusb_unref_device(info.rawDevice.(*C.libusb_device))
+ }
+ // If enumeration failed, don't return anything, otherwise everything
+ if err != nil {
+ return nil, err
+ }
+ return infos, nil
+}
+
+// enumerateRawWithRef is the internal device enumerator that retains 1 reference
+// to every matched device so they may selectively be opened on request.
+func enumerateRawWithRef(vendorID uint16, productID uint16) ([]DeviceInfo, error) {
+ // Ensure we have a libusb context to interact through. The enumerate call is
+ // protexted by a mutex outside, so it's fine to do the below check and init.
+ if C.ctx == nil {
+ if err := fromRawErrno(C.libusb_init((**C.libusb_context)(&C.ctx))); err != nil {
+ return nil, fmt.Errorf("failed to initialize libusb: %v", err)
+ }
+ }
+ // Retrieve all the available USB devices and wrap them in Go
+ var deviceList **C.libusb_device
+ count := C.libusb_get_device_list(C.ctx, &deviceList)
+ if count < 0 {
+ return nil, rawError(count)
+ }
+ defer C.libusb_free_device_list(deviceList, 1)
+
+ var devices []*C.libusb_device
+ *(*reflect.SliceHeader)(unsafe.Pointer(&devices)) = reflect.SliceHeader{
+ Data: uintptr(unsafe.Pointer(deviceList)),
+ Len: int(count),
+ Cap: int(count),
+ }
+ //
+ var infos []DeviceInfo
+ for devnum, dev := range devices {
+ // Retrieve the libusb device descriptor and skip non-queried ones
+ var desc C.struct_libusb_device_descriptor
+ if err := fromRawErrno(C.libusb_get_device_descriptor(dev, &desc)); err != nil {
+ return infos, fmt.Errorf("failed to get device %d descriptor: %v", devnum, err)
+ }
+ if (vendorID > 0 && uint16(desc.idVendor) != vendorID) || (productID > 0 && uint16(desc.idProduct) != productID) {
+ continue
+ }
+ // Skip HID devices, they are handled directly by OS libraries
+ if desc.bDeviceClass == C.LIBUSB_CLASS_HID {
+ continue
+ }
+ // Iterate over all the configurations and find raw interfaces
+ for cfgnum := 0; cfgnum < int(desc.bNumConfigurations); cfgnum++ {
+ // Retrieve the all the possible USB configurations of the device
+ var cfg *C.struct_libusb_config_descriptor
+ if err := fromRawErrno(C.libusb_get_config_descriptor(dev, C.uint8_t(cfgnum), &cfg)); err != nil {
+ return infos, fmt.Errorf("failed to get device %d config %d: %v", devnum, cfgnum, err)
+ }
+ var ifaces []C.struct_libusb_interface
+ *(*reflect.SliceHeader)(unsafe.Pointer(&ifaces)) = reflect.SliceHeader{
+ Data: uintptr(unsafe.Pointer(cfg._interface)),
+ Len: int(cfg.bNumInterfaces),
+ Cap: int(cfg.bNumInterfaces),
+ }
+ // Drill down into each advertised interface
+ for ifacenum, iface := range ifaces {
+ if iface.num_altsetting == 0 {
+ continue
+ }
+ var alts []C.struct_libusb_interface_descriptor
+ *(*reflect.SliceHeader)(unsafe.Pointer(&alts)) = reflect.SliceHeader{
+ Data: uintptr(unsafe.Pointer(iface.altsetting)),
+ Len: int(iface.num_altsetting),
+ Cap: int(iface.num_altsetting),
+ }
+ for _, alt := range alts {
+ // Skip HID interfaces, they are handled directly by OS libraries
+ if alt.bInterfaceClass == C.LIBUSB_CLASS_HID {
+ continue
+ }
+ // Find the endpoints that can speak libusb interrupts
+ var ends []C.struct_libusb_endpoint_descriptor
+ *(*reflect.SliceHeader)(unsafe.Pointer(&ends)) = reflect.SliceHeader{
+ Data: uintptr(unsafe.Pointer(alt.endpoint)),
+ Len: int(alt.bNumEndpoints),
+ Cap: int(alt.bNumEndpoints),
+ }
+ var reader, writer *uint8
+ for _, end := range ends {
+ // Skip any non-interrupt endpoints
+ if end.bmAttributes != C.LIBUSB_TRANSFER_TYPE_INTERRUPT {
+ continue
+ }
+ if end.bEndpointAddress&C.LIBUSB_ENDPOINT_IN == C.LIBUSB_ENDPOINT_IN {
+ reader = new(uint8)
+ *reader = uint8(end.bEndpointAddress)
+ } else {
+ writer = new(uint8)
+ *writer = uint8(end.bEndpointAddress)
+ }
+ }
+ // If both in and out interrupts are available, match the device
+ if reader != nil && writer != nil {
+ // Enumeration matched, bump the device refcount to avoid cleaning it up
+ C.libusb_ref_device(dev)
+
+ port := uint8(C.libusb_get_port_number(dev))
+ infos = append(infos, DeviceInfo{
+ Path: fmt.Sprintf("%04x:%04x:%02d", vendorID, uint16(desc.idProduct), port),
+ VendorID: uint16(desc.idVendor),
+ ProductID: uint16(desc.idProduct),
+ Interface: ifacenum,
+ rawDevice: dev,
+ rawPort: &port,
+ rawReader: reader,
+ rawWriter: writer,
+ })
+ }
+ }
+ }
+ }
+ }
+ return infos, nil
+}
+
+// openRaw connects to a low level libusb device by its path name.
+func openRaw(info DeviceInfo) (*rawDevice, error) {
+ // Enumerate all the devices matching this particular info
+ matches, err := enumerateRawWithRef(info.VendorID, info.ProductID)
+ if err != nil {
+ // Enumeration failed, make sure any subresults are released
+ for _, match := range matches {
+ C.libusb_unref_device(match.rawDevice.(*C.libusb_device))
+ }
+ return nil, err
+ }
+ // Find the specific endpoint we're interested in
+ var device *C.libusb_device
+ for _, match := range matches {
+ // Keep the matching device reference, release anything else
+ if device == nil && *match.rawPort == *info.rawPort && match.Interface == info.Interface {
+ device = match.rawDevice.(*C.libusb_device)
+ } else {
+ C.libusb_unref_device(match.rawDevice.(*C.libusb_device))
+ }
+ }
+ if device == nil {
+ return nil, fmt.Errorf("failed to open device: not found")
+ }
+ // Open the mathcing device
+ info.rawDevice = device
+
+ var handle *C.struct_libusb_device_handle
+ if err := fromRawErrno(C.libusb_open(info.rawDevice.(*C.libusb_device), (**C.struct_libusb_device_handle)(&handle))); err != nil {
+ return nil, fmt.Errorf("failed to open device: %v", err)
+ }
+ if err := fromRawErrno(C.libusb_claim_interface(handle, (C.int)(info.Interface))); err != nil {
+ C.libusb_close(handle)
+ return nil, fmt.Errorf("failed to claim interface: %v", err)
+ }
+ return &rawDevice{
+ DeviceInfo: info,
+ handle: handle,
+ }, nil
+}
+
+// rawDevice is a live low level USB connected device handle.
+type rawDevice struct {
+ DeviceInfo // Embed the infos for easier access
+
+ handle *C.struct_libusb_device_handle // Low level USB device to communicate through
+ lock sync.Mutex
+}
+
+// Close releases the raw USB device handle.
+func (dev *rawDevice) Close() error {
+ dev.lock.Lock()
+ defer dev.lock.Unlock()
+
+ if dev.handle != nil {
+ C.libusb_release_interface(dev.handle, (C.int)(dev.Interface))
+ C.libusb_close(dev.handle)
+ dev.handle = nil
+ }
+ C.libusb_unref_device(dev.rawDevice.(*C.libusb_device))
+
+ return nil
+}
+
+// Write sends a binary blob to a low level USB device.
+func (dev *rawDevice) Write(b []byte) (int, error) {
+ dev.lock.Lock()
+ defer dev.lock.Unlock()
+
+ var transferred C.int
+ if err := fromRawErrno(C.libusb_interrupt_transfer(dev.handle, (C.uchar)(*dev.rawWriter), (*C.uchar)(&b[0]), (C.int)(len(b)), &transferred, (C.uint)(0))); err != nil {
+ return 0, fmt.Errorf("failed to write to device: %v", err)
+ }
+ return int(transferred), nil
+}
+
+// Read retrieves a binary blob from a low level USB device.
+func (dev *rawDevice) Read(b []byte) (int, error) {
+ dev.lock.Lock()
+ defer dev.lock.Unlock()
+
+ var transferred C.int
+ if err := fromRawErrno(C.libusb_interrupt_transfer(dev.handle, (C.uchar)(*dev.rawReader), (*C.uchar)(&b[0]), (C.int)(len(b)), &transferred, (C.uint)(0))); err != nil {
+ return 0, fmt.Errorf("failed to read from device: %v", err)
+ }
+ return int(transferred), nil
+}
diff --git a/vendor/github.com/karalabe/usb/raw_errors.go b/vendor/github.com/karalabe/usb/raw_errors.go
new file mode 100644
index 000000000..9e071f861
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/raw_errors.go
@@ -0,0 +1,74 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import (
+ "fmt"
+)
+
+// #include "./libusb/libusb/libusb.h"
+import "C"
+
+// rawError is an error code from libusb.
+type rawError C.int
+
+// Error implements the error interface.
+func (e rawError) Error() string {
+ return fmt.Sprintf("libusb: %s [code %d]", rawErrorString[e], e)
+}
+
+// fromRawErrno converts a raw libusb error into a Go type.
+func fromRawErrno(errno C.int) error {
+ err := rawError(errno)
+ if err == errSuccess {
+ return nil
+ }
+ return err
+}
+
+const (
+ errSuccess rawError = C.LIBUSB_SUCCESS
+ errIO rawError = C.LIBUSB_ERROR_IO
+ errInvalidParam rawError = C.LIBUSB_ERROR_INVALID_PARAM
+ errAccess rawError = C.LIBUSB_ERROR_ACCESS
+ errNoDevice rawError = C.LIBUSB_ERROR_NO_DEVICE
+ errNotFound rawError = C.LIBUSB_ERROR_NOT_FOUND
+ errBusy rawError = C.LIBUSB_ERROR_BUSY
+ errTimeout rawError = C.LIBUSB_ERROR_TIMEOUT
+ errOverflow rawError = C.LIBUSB_ERROR_OVERFLOW
+ errPipe rawError = C.LIBUSB_ERROR_PIPE
+ errInterrupted rawError = C.LIBUSB_ERROR_INTERRUPTED
+ errNoMem rawError = C.LIBUSB_ERROR_NO_MEM
+ errNotSupported rawError = C.LIBUSB_ERROR_NOT_SUPPORTED
+ errOther rawError = C.LIBUSB_ERROR_OTHER
+)
+
+var rawErrorString = map[rawError]string{
+ errSuccess: "success",
+ errIO: "i/o error",
+ errInvalidParam: "invalid param",
+ errAccess: "bad access",
+ errNoDevice: "no device",
+ errNotFound: "not found",
+ errBusy: "device or resource busy",
+ errTimeout: "timeout",
+ errOverflow: "overflow",
+ errPipe: "pipe error",
+ errInterrupted: "interrupted",
+ errNoMem: "out of memory",
+ errNotSupported: "not supported",
+ errOther: "unknown error",
+}
diff --git a/vendor/github.com/karalabe/usb/usb.go b/vendor/github.com/karalabe/usb/usb.go
new file mode 100644
index 000000000..96a1e2502
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/usb.go
@@ -0,0 +1,68 @@
+// usb - Self contained USB and HID library for Go
+// Copyright 2019 The library Authors
+//
+// This library is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// The library is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License along
+// with the library. If not, see <http://www.gnu.org/licenses/>.
+
+// Package usb provide interfaces for generic USB devices.
+package usb
+
+import "errors"
+
+// ErrDeviceClosed is returned for operations where the device closed before or
+// during the execution.
+var ErrDeviceClosed = errors.New("usb: device closed")
+
+// ErrUnsupportedPlatform is returned for all operations where the underlying
+// operating system is not supported by the library.
+var ErrUnsupportedPlatform = errors.New("usb: unsupported platform")
+
+// DeviceInfo contains all the information we know about a USB device. In case of
+// HID devices, that might be a lot more extensive (empty fields for raw USB).
+type DeviceInfo 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
+
+ // Raw low level libusb endpoint data for simplified communication
+ rawDevice interface{}
+ rawPort *uint8 // Pointer to differentiate between unset and port 0
+ rawReader *uint8 // Pointer to differentiate between unset and endpoint 0
+ rawWriter *uint8 // Pointer to differentiate between unset and endpoint 0
+}
+
+// Device is a generic USB device interface. It may either be backed by a USB HID
+// device or a low level raw (libusb) device.
+type Device interface {
+ // Close releases the USB device handle.
+ Close() error
+
+ // Write sends a binary blob to a USB device. For HID devices write uses reports,
+ // for low level USB write uses interrupt transfers.
+ Write(b []byte) (int, error)
+
+ // Read retrieves a binary blob from a USB device. For HID devices read uses
+ // reports, for low level USB read uses interrupt transfers.
+ Read(b []byte) (int, error)
+}
diff --git a/vendor/github.com/karalabe/usb/usb_disabled.go b/vendor/github.com/karalabe/usb/usb_disabled.go
new file mode 100644
index 000000000..39259856e
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/usb_disabled.go
@@ -0,0 +1,46 @@
+// usb - Self contained USB and HID library for Go
+// Copyright 2019 The library Authors
+//
+// This library is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// The library is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License along
+// with the library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build !freebsd,!linux,!darwin,!windows ios !cgo
+
+package usb
+
+// Supported returns whether this platform is supported by the USB library or not.
+// The goal of this method is to allow programatically handling platforms that do
+// not support USB and not having to fall back to build constraints.
+func Supported() bool {
+ return false
+}
+
+// Enumerate returns a list of all the USB devices attached to the system which
+// match the vendor and product id. On platforms that this file implements the
+// function is a noop and returns an empty list always.
+func Enumerate(vendorID uint16, productID uint16) []DeviceInfo {
+ return nil
+}
+
+// EnumerateRaw returns a list of all the USB devices attached to the system which
+// match the vendor and product id. On platforms that this file implements the
+// function is a noop and returns an empty list always.
+func EnumerateRaw(vendorID uint16, productID uint16) ([]DeviceInfo, error) {
+ return nil
+}
+
+// EnumerateHid returns a list of all the HID devices attached to the system which
+// match the vendor and product id. On platforms that this file implements the
+// function is a noop and returns an empty list always.
+func EnumerateHid(vendorID uint16, productID uint16) ([]DeviceInfo, error) {
+ return nil
+}
diff --git a/vendor/github.com/karalabe/usb/usb_enabled.go b/vendor/github.com/karalabe/usb/usb_enabled.go
new file mode 100644
index 000000000..6ba37af7b
--- /dev/null
+++ b/vendor/github.com/karalabe/usb/usb_enabled.go
@@ -0,0 +1,98 @@
+// usb - Self contained USB and HID library for Go
+// Copyright 2019 The library Authors
+//
+// This library is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// The library is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License along
+// with the library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build freebsd,cgo linux,cgo darwin,!ios,cgo windows,cgo
+
+package usb
+
+import (
+ "sync"
+)
+
+// 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
+
+// Supported returns whether this platform is supported by the USB library or not.
+// The goal of this method is to allow programatically handling platforms that do
+// not support USB and not having to fall back to build constraints.
+func Supported() bool {
+ return true
+}
+
+// Enumerate returns a list of all the USB 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 devices are returned.
+//
+// For any device that is HID capable, the enumeration will return an interface
+// to the HID endpoints. For pure raw USB access, please use EnumerateRaw.
+func Enumerate(vendorID uint16, productID uint16) ([]DeviceInfo, error) {
+ enumerateLock.Lock()
+ defer enumerateLock.Unlock()
+
+ // Enumerate all the raw USB devices and skip the HID ones
+ raws, err := enumerateRaw(vendorID, productID)
+ if err != nil {
+ return nil, err
+ }
+ // Enumerate all the HID USB devices
+ hids, err := enumerateHid(vendorID, productID)
+ if err != nil {
+ return nil, err
+ }
+ return append(raws, hids...), nil
+}
+
+// EnumerateRaw returns a list of all the USB 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 devices are returned.
+func EnumerateRaw(vendorID uint16, productID uint16) ([]DeviceInfo, error) {
+ enumerateLock.Lock()
+ defer enumerateLock.Unlock()
+
+ return enumerateRaw(vendorID, productID)
+}
+
+// EnumerateHid 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 devices are returned.
+func EnumerateHid(vendorID uint16, productID uint16) ([]DeviceInfo, error) {
+ enumerateLock.Lock()
+ defer enumerateLock.Unlock()
+
+ return enumerateHid(vendorID, productID)
+}
+
+// Open connects to a previsouly discovered USB device.
+func (info DeviceInfo) Open() (Device, error) {
+ enumerateLock.Lock()
+ defer enumerateLock.Unlock()
+
+ if info.rawDevice == nil {
+ return openHid(info)
+ }
+ return openRaw(info)
+}
diff --git a/vendor/github.com/karalabe/hid/wchar.go b/vendor/github.com/karalabe/usb/wchar.go
index d103beff5..cbc7e4d56 100644
--- a/vendor/github.com/karalabe/hid/wchar.go
+++ b/vendor/github.com/karalabe/usb/wchar.go
@@ -7,9 +7,9 @@
// https://github.com/orofarne/gowchar/blob/master/LICENSE
// +build !ios
-// +build linux darwin windows
+// +build freebsd linux darwin windows
-package hid
+package usb
/*
#include <wchar.h>
diff --git a/vendor/vendor.json b/vendor/vendor.json
index a33a1d4e2..6e1624306 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -159,16 +159,16 @@
"revisionTime": "2017-07-10T16:04:46Z"
},
{
- "checksumSHA1": "yqF125xVSkmfLpIVGrLlfE05IUk=",
+ "checksumSHA1": "CGj8VcI/CpzxaNqlqpEVM7qElD4=",
"path": "github.com/golang/protobuf/proto",
- "revision": "748d386b5c1ea99658fd69fe9f03991ce86a90c1",
- "revisionTime": "2017-07-26T21:28:29Z"
+ "revision": "b285ee9cfc6c881bb20c0d8dc73370ea9b9ec90f",
+ "revisionTime": "2019-05-17T06:12:10Z"
},
{
- "checksumSHA1": "Z1gJ3PKzwBpOoPnTSEM5yd0zHYA=",
+ "checksumSHA1": "WOkXetG3AqJnfVVuqTJvdukcHps=",
"path": "github.com/golang/protobuf/protoc-gen-go/descriptor",
- "revision": "748d386b5c1ea99658fd69fe9f03991ce86a90c1",
- "revisionTime": "2017-07-26T21:28:29Z"
+ "revision": "b285ee9cfc6c881bb20c0d8dc73370ea9b9ec90f",
+ "revisionTime": "2019-05-17T06:12:10Z"
},
{
"checksumSHA1": "p/8vSviYF91gFflhrt5vkyksroo=",
@@ -267,10 +267,10 @@
"revisionTime": "2017-04-30T22:20:11Z"
},
{
- "checksumSHA1": "6XsjAARQFvlW6dS15al0ibTFPOQ=",
- "path": "github.com/karalabe/hid",
- "revision": "d815e0c1a2e2082a287a2806bc90bc8fc7b276a9",
- "revisionTime": "2018-11-28T19:21:57Z",
+ "checksumSHA1": "3v8Z4/daUVp9PCcFzEGYVkPadG8=",
+ "path": "github.com/karalabe/usb",
+ "revision": "c012609e094b8a96375fee53cc11f1bcd5cf3aa2",
+ "revisionTime": "2019-06-04T10:57:36Z",
"tree": true
},
{