implementing an improperly created fork in a semi-proper manner after excessive bashing of head into keyboard - it works

This commit is contained in:
kayos 2021-05-12 17:34:38 -07:00
parent 50f9df3934
commit f7667fb4e8
715 changed files with 12 additions and 232092 deletions

5
go.mod
View File

@ -3,13 +3,14 @@ module protomolecule
go 1.16
require (
git.tcp.direct/kayos/prototooth v0.3.1-0.20210513000132-e440008138af
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/godbus/dbus/v5 v5.0.4 // indirect
github.com/muka/go-bluetooth v0.0.0-20201211051136-07f31c601d33 // indirect
github.com/prologic/bitcask v0.3.10
github.com/pterm/pterm v0.12.14
github.com/rs/zerolog v1.21.0
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/stretchr/testify v1.7.0 // indirect
golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0 // indirect
tinygo.org/x/bluetooth v0.3.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)

22
go.sum
View File

@ -11,6 +11,8 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.tcp.direct/kayos/prototooth v0.3.1-0.20210513000132-e440008138af h1:+J2MfTQvW1DmX1HYIQUsrCd5l0Il9JMYTOowIs8ju1Y=
git.tcp.direct/kayos/prototooth v0.3.1-0.20210513000132-e440008138af/go.mod h1:kk4oyPgWq6Rijn30Js4ITQC5DFwmpyzWL3+8V6q9wdM=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/JuulLabs-OSS/cbgo v0.0.2 h1:gCDyT0+EPuI8GOFyvAksFcVD2vF4CXBAVwT6uVnD9oo=
@ -82,8 +84,6 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gookit/color v1.4.1 h1:MIizA5j/X2Vb+lWXnjxu3Xav+u5OdqwKMUqrRHNaAmQ=
github.com/gookit/color v1.4.1/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@ -125,14 +125,11 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@ -149,7 +146,6 @@ github.com/muka/go-bluetooth v0.0.0-20200619025933-f6113f7141c5/go.mod h1:yV39+E
github.com/muka/go-bluetooth v0.0.0-20201211051136-07f31c601d33 h1:p3srutpE8TpQmOUQ5Qw94jYFUdoG2jBbILeYLroQNoI=
github.com/muka/go-bluetooth v0.0.0-20201211051136-07f31c601d33/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@ -176,11 +172,6 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/pterm/pterm v0.12.14 h1:iCBoFtfhpn7vLuE8dAzA/vzijfolP7oEdh/jv/1nHg4=
github.com/pterm/pterm v0.12.14/go.mod h1:kJLnbnOAnwSaee/6kMVtoLr4avzShsFJUAHedynGJ4g=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@ -229,8 +220,6 @@ github.com/tidwall/redcon v1.4.0/go.mod h1:IGzxyoKE3Ea5AWIXo/ZHP+hzY8sWXaMKr7KlF
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@ -319,13 +308,9 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0 h1:g9s1Ppvvun/fI+BptTMj909BBIcGrzQ32k9FNlcevOE=
golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -382,7 +367,6 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@ -402,6 +386,4 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
tinygo.org/x/bluetooth v0.3.0 h1:xy6f1aCAA5VzaXcx+qs4od6ZpiNu6pa/ufnZP7Db2ss=
tinygo.org/x/bluetooth v0.3.0/go.mod h1:zg3FxlQIY6vtbtpK5dU8h5BzQiLoE3hGthXTR0GNEn0=
tinygo.org/x/drivers v0.15.1/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=

View File

@ -12,7 +12,7 @@ import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
//"tinygo.org/x/bluetooth"
//"git.tcp.direct/kayos/prototooth"
)
var ScanMgr *scanStuff.Meta

View File

@ -1,6 +1,6 @@
package blueStuff
import "tinygo.org/x/bluetooth"
//import "git.tcp.direct/kayos/prototooth"
//controls connections to found devices to get service characteristics
@ -9,7 +9,7 @@ import "tinygo.org/x/bluetooth"
// once connected, for list of service characteristics and check for read / write for each
// loog all of this to eros
func pathways(target bluetooth.ScanResult) {
/*func pathways(target bluetooth.ScanResult) {
println("Discovery")
@ -17,4 +17,4 @@ func pathways(target bluetooth.ScanResult) {
//srvcs, err := projVars.ScanAdapter.
}
}*/

View File

@ -8,7 +8,8 @@ import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"tinygo.org/x/bluetooth"
"git.tcp.direct/kayos/prototooth"
"time"
)

View File

@ -4,7 +4,7 @@ import (
"flag"
"github.com/rs/zerolog"
"tinygo.org/x/bluetooth"
"git.tcp.direct/kayos/prototooth"
)
//The initial list of device in the area

View File

@ -1 +0,0 @@
examples/discover/discover

View File

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

View File

@ -1,25 +0,0 @@
# cbgo
cbgo implements Go bindings for [CoreBluetooth](https://developer.apple.com/documentation/corebluetooth?language=objc).
## Documentation
For documentation, see the [CoreBluetooth docs](https://developer.apple.com/documentation/corebluetooth?language=objc).
Examples are in the `examples` directory.
## Scope
cbgo aims to implement all functionality that is supported in macOS 10.13.
## Naming
Function and type names in cbgo are intended to match the corresponding CoreBluetooth functionality as closely as possible. There are a few (consistent) deviations:
* All cbgo identifiers start with a capital letter to make them public.
* Named arguments in CoreBluetooth functions are eliminated.
* Properties are implemented as a pair of functions (`PropertyName` and `SetPropertyName`).
## Issues
There are definitely memory leaks. ARC is not compatible with cgo, so objective C memory has to be managed manually. I didn't see a set of consistent guidelines for object ownership in the CoreBluetooth documentation, so cbgo errs on the side of leaking. Hopefully this is only an issue for very long running processes! Any fixes here are much appreciated.

View File

@ -1,26 +0,0 @@
package cbgo
type AdvServiceData struct {
UUID UUID
Data []byte
}
// AdvFields represents the contents of an advertisement received during
// scanning.
type AdvFields struct {
LocalName string
ManufacturerData []byte
TxPowerLevel *int
Connectable *bool
ServiceUUIDs []UUID
ServiceData []AdvServiceData
}
// AdvData represents the configurable portion of outgoing advertisements.
type AdvData struct {
LocalName string
ServiceUUIDs []UUID
// If len>0, this overrides the other fields.
IBeaconData []byte
}

View File

@ -1,78 +0,0 @@
package cbgo
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
import "unsafe"
// AttributePermissions: https://developer.apple.com/documentation/corebluetooth/cbattributepermissions
type AttributePermissions int
const (
AttributePermissionsReadable = AttributePermissions(C.CBAttributePermissionsReadable)
AttributePermissionsWriteable = AttributePermissions(C.CBAttributePermissionsWriteable)
AttributePermissionsReadEncryptionRequired = AttributePermissions(C.CBAttributePermissionsReadEncryptionRequired)
AttributePermissionsWriteEncryptionRequired = AttributePermissions(C.CBAttributePermissionsWriteEncryptionRequired)
)
// ATTError: https://developer.apple.com/documentation/corebluetooth/cbatterror
type ATTError int
const (
ATTErrorSuccess = ATTError(C.CBATTErrorSuccess)
ATTErrorInvalidHandle = ATTError(C.CBATTErrorInvalidHandle)
ATTErrorReadNotPermitted = ATTError(C.CBATTErrorReadNotPermitted)
ATTErrorWriteNotPermitted = ATTError(C.CBATTErrorWriteNotPermitted)
ATTErrorInvalidPdu = ATTError(C.CBATTErrorInvalidPdu)
ATTErrorInsufficientAuthentication = ATTError(C.CBATTErrorInsufficientAuthentication)
ATTErrorRequestNotSupported = ATTError(C.CBATTErrorRequestNotSupported)
ATTErrorInvalidOffset = ATTError(C.CBATTErrorInvalidOffset)
ATTErrorInsufficientAuthorization = ATTError(C.CBATTErrorInsufficientAuthorization)
ATTErrorPrepareQueueFull = ATTError(C.CBATTErrorPrepareQueueFull)
ATTErrorAttributeNotFound = ATTError(C.CBATTErrorAttributeNotFound)
ATTErrorAttributeNotLong = ATTError(C.CBATTErrorAttributeNotLong)
ATTErrorInsufficientEncryptionKeySize = ATTError(C.CBATTErrorInsufficientEncryptionKeySize)
ATTErrorInvalidAttributeValueLength = ATTError(C.CBATTErrorInvalidAttributeValueLength)
ATTErrorUnlikelyError = ATTError(C.CBATTErrorUnlikelyError)
ATTErrorInsufficientEncryption = ATTError(C.CBATTErrorInsufficientEncryption)
ATTErrorUnsupportedGroupType = ATTError(C.CBATTErrorUnsupportedGroupType)
ATTErrorInsufficientResources = ATTError(C.CBATTErrorInsufficientResources)
)
// ATTRequest: https://developer.apple.com/documentation/corebluetooth/cbattrequest
type ATTRequest struct {
ptr unsafe.Pointer
}
// Central: https://developer.apple.com/documentation/corebluetooth/cbattrequest/1518995-central
func (r ATTRequest) Central() Central {
ptr := C.cb_atr_central(r.ptr)
return Central{unsafe.Pointer(ptr)}
}
// Characteristic: https://developer.apple.com/documentation/corebluetooth/cbattrequest/1518716-characteristic
func (r ATTRequest) Characteristic() Characteristic {
ptr := C.cb_atr_characteristic(r.ptr)
return Characteristic{unsafe.Pointer(ptr)}
}
// Value: https://developer.apple.com/documentation/corebluetooth/cbattrequest/1518795-value
func (r ATTRequest) Value() []byte {
ba := C.cb_atr_value(r.ptr)
return byteArrToByteSlice(&ba)
}
// SetValue: https://developer.apple.com/documentation/corebluetooth/cbattrequest/1518795-value
func (r ATTRequest) SetValue(v []byte) {
ba := byteSliceToByteArr(v)
defer C.free(unsafe.Pointer(ba.data))
C.cb_atr_set_value(r.ptr, &ba)
}
// Offset: https://developer.apple.com/documentation/corebluetooth/cbattrequest/1518857-offset
func (r ATTRequest) Offset() int {
return int(C.cb_atr_offset(r.ptr))
}

View File

@ -1,28 +0,0 @@
package cbgo
import (
"os"
"github.com/sirupsen/logrus"
)
var btlog = &logrus.Logger{
Out: os.Stderr,
Formatter: &logrus.TextFormatter{
FullTimestamp: true,
TimestampFormat: "2006-01-02 15:04:05.999",
},
Level: logrus.ErrorLevel,
}
// SetLog replaces the cbgo logger with a custom one.
func SetLog(log *logrus.Logger) {
btlog = log
}
// SetLogLevel configures the cbgo logger to use the specified log level.
func SetLogLevel(level logrus.Level) {
if btlog != nil {
btlog.SetLevel(level)
}
}

View File

@ -1,220 +0,0 @@
#ifndef H_BT_
#define H_BT_
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
#define ADV_FIELDS_PWR_LVL_NONE (-128)
#define ADV_FIELDS_CONNECTABLE_NONE (-1)
struct byte_arr {
const uint8_t *data;
int length;
};
struct string_arr {
const char **strings;
int count;
};
struct obj_arr {
void **objs;
int count;
};
struct bt_error {
const char *msg;
int code;
};
struct adv_fields {
const char *name;
struct byte_arr mfg_data;
struct string_arr svc_uuids;
struct string_arr overflow_svc_uuids;
int8_t pwr_lvl; // -128 = not present
int connectable; // -1 = not present
struct string_arr svc_data_uuids;
struct byte_arr *svc_data_values;
};
struct adv_data {
const char *name;
struct string_arr svc_uuids;
struct byte_arr ibeacon_data;
};
struct scan_opts {
bool allow_dups;
struct string_arr sol_svc_uuids;
};
struct connect_opts {
bool notify_on_connection;
bool notify_on_disconnection;
bool notify_on_notification;
bool enable_transport_bridging;
bool requires_ancs;
int start_delay;
};
struct cmgr_restore_opts {
struct obj_arr prphs;
struct string_arr scan_svcs;
struct scan_opts *scan_opts;
};
struct pmgr_restore_opts {
struct obj_arr svcs;
struct adv_data *adv_data;
};
@interface BTDlg : NSObject <CBCentralManagerDelegate, CBPeripheralManagerDelegate, CBPeripheralDelegate>
{
}
@end
// bt.m
bool bt_start();
void bt_stop();
void bt_init();
// util.m
struct byte_arr nsdata_to_byte_arr(const NSData *nsdata);
NSData *byte_arr_to_nsdata(const struct byte_arr *ba);
struct obj_arr nsarray_to_obj_arr(const NSArray *arr);
NSArray *obj_arr_to_nsarray(const struct obj_arr *oa);
NSString *str_to_nsstring(const char *s);
struct bt_error nserror_to_bt_error(const NSError *err);
struct string_arr cbuuids_to_strs(const NSArray *cbuuids);
int dict_int(NSDictionary *dict, NSString *key, int dflt);
const char *dict_string(NSDictionary *dict, NSString *key);
const void *dict_data(NSDictionary *dict, NSString *key, int *out_len);
const struct byte_arr dict_bytes(NSDictionary *dict, NSString *key);
void dict_set_bool(NSMutableDictionary *dict, NSString *key, bool val);
void dict_set_int(NSMutableDictionary *dict, NSString *key, int val);
NSUUID *str_to_nsuuid(const char *s);
CBUUID *str_to_cbuuid(const char *s);
NSArray *strs_to_nsuuids(const struct string_arr *sa);
NSArray *strs_to_cbuuids(const struct string_arr *sa);
NSArray *strs_to_nsstrings(const struct string_arr *sa);
// cmgr.m
CBCentralManager *cb_alloc_cmgr(bool pwr_alert, const char *restore_id);
void cb_cmgr_set_delegate(void *cmgr, bool set);
int cb_cmgr_state(void *cm);
void cb_cmgr_scan(void *cmgr, const struct string_arr *svc_uuids,
const struct scan_opts *opts);
void cb_cmgr_stop_scan(void *cm);
bool cb_cmgr_is_scanning(void *cm);
void cb_cmgr_connect(void *cmgr, void *prph, const struct connect_opts *opts);
void cb_cmgr_cancel_connect(void *cmgr, void *prph);
struct obj_arr cb_cmgr_retrieve_prphs_with_svcs(void *cmgr, const struct string_arr *svc_uuids);
struct obj_arr cb_cmgr_retrieve_prphs(void *cmgr, const struct string_arr *uuids);
const char *cb_peer_identifier(void *prph);
void cb_prph_set_delegate(void *prph, bool set);
const char *cb_prph_name(void *prph);
struct obj_arr cb_prph_services(void *prph);
void cb_prph_discover_svcs(void *prph, const struct string_arr *svc_uuid_strs);
void cb_prph_discover_included_svcs(void *prph, const struct string_arr *svc_uuid_strs, void *svc);
void cb_prph_discover_chrs(void *prph, void *svc, const struct string_arr *chr_uuid_strs);
void cb_prph_discover_dscs(void *prph, void *chr);
void cb_prph_read_chr(void *prph, void *chr);
void cb_prph_read_dsc(void *prph, void *dsc);
void cb_prph_write_chr(void *prph, void *chr, struct byte_arr *value, int type);
void cb_prph_write_dsc(void *prph, void *dsc, struct byte_arr *value);
int cb_prph_max_write_len(void *prph, int type);
void cb_prph_set_notify(void *prph, bool enabled, void *chr);
int cb_prph_state(void *prph);
bool cb_prph_can_send_write_without_rsp(void *prph);
void cb_prph_read_rssi(void *prph);
bool cb_prph_ancs_authorized(void *prph);
const char *cb_svc_uuid(void *svc);
void *cb_svc_peripheral(void *svc);
bool cb_svc_is_primary(void *svc);
struct obj_arr cb_svc_characteristics(void *svc);
struct obj_arr cb_svc_included_svcs(void *svc);
const char *cb_chr_uuid(void *chr);
void *cb_chr_service(void *chr);
struct obj_arr cb_chr_descriptors(void *chr);
struct byte_arr cb_chr_value(void *chr);
int cb_chr_properties(void *chr);
bool cb_chr_is_notifying(void *chr);
const char *cb_dsc_uuid(void *dsc);
void *cb_dsc_characteristic(void *dsc);
struct byte_arr cb_dsc_value(void *dsc);
// pmgr.m
CBPeripheralManager *cb_alloc_pmgr(bool pwr_alert, const char *restore_id);
void cb_pmgr_set_delegate(void *pmgr, bool set);
int cb_pmgr_state(void *pmgr);
void cb_pmgr_add_svc(void *pmgr, void *svc);
void cb_pmgr_remove_svc(void *pmgr, void *svc);
void cb_pmgr_remove_all_svcs(void *pmgr);
void cb_pmgr_start_adv(void *pmgr, const struct adv_data *ad);
void cb_pmgr_stop_adv(void *pmgr);
bool cb_pmgr_is_adv(void *pmgr);
bool cb_pmgr_update_val(void *pmgr, const struct byte_arr *value, void *chr, const struct obj_arr *centrals);
void cb_pmgr_respond_to_req(void *pmgr, void *req, int result);
void cb_pmgr_set_conn_latency(void *pmgr, int latency, void *central);
int cb_cent_maximum_update_len(void *cent);
CBMutableService *cb_msvc_alloc(const char *uuid, bool primary);
void cb_msvc_set_characteristics(void *msvc, const struct obj_arr *mchrs);
void cb_msvc_set_included_services(void *msvc, const struct obj_arr *msvcs);
CBMutableCharacteristic *cb_mchr_alloc(const char *uuid, int properties, const struct byte_arr *value,
int permissions);
void cb_mchr_set_value(void *mchr, const struct byte_arr *val);
void cb_mchr_set_descriptors(void *mchr, const struct obj_arr *mdscs);
CBMutableDescriptor *cb_mdsc_alloc(const char *uuid, const struct byte_arr *value);
CBCentral *cb_atr_central(void *atr);
CBCharacteristic *cb_atr_characteristic(void *atr);
struct byte_arr cb_atr_value(void *atr);
void cb_atr_set_value(void *atr, const struct byte_arr *ba);
int cb_atr_offset(void *atr);
// cbhandlers.go
void BTCentralManagerDidConnectPeripheral(void *cmgr, void *prph);
void BTCentralManagerDidFailToConnectPeripheral(void *cmgr, void *prph, struct bt_error *err);
void BTCentralManagerDidDisconnectPeripheral(void *cmgr, void *prph, struct bt_error *err);
void BTCentralManagerConnectionEventDidOccur(void *cmgr, int event, void *prph);
void BTCentralManagerDidDiscoverPeripheral(void *cmgr, void *prph, struct adv_fields *advData, int rssi);
void BTCentralManagerDidUpdateState(void *cmgr);
void BTCentralManagerWillRestoreState(void *cmgr, struct cmgr_restore_opts *opts);
void BTPeripheralDidDiscoverServices(void *prph, struct bt_error *err);
void BTPeripheralDidDiscoverIncludedServices(void *prph, void *svc, struct bt_error *err);
void BTPeripheralDidDiscoverCharacteristics(void *prph, void *svc, struct bt_error *err);
void BTPeripheralDidDiscoverDescriptors(void *prph, void *chr, struct bt_error *err);
void BTPeripheralDidUpdateValueForCharacteristic(void *prph, void *chr, struct bt_error *err);
void BTPeripheralDidUpdateValueForDescriptor(void *prph, void *dsc, struct bt_error *err);
void BTPeripheralDidWriteValueForCharacteristic(void *prph, void *chr, struct bt_error *err);
void BTPeripheralDidWriteValueForDescriptor(void *prph, void *dsc, struct bt_error *err);
void BTPeripheralIsReadyToSendWriteWithoutResponse(void *prph);
void BTPeripheralDidUpdateNotificationState(void *prph, void *chr, struct bt_error *err);
void BTPeripheralDidReadRSSI(void *prph, int rssi, struct bt_error *err);
void BTPeripheralDidUpdateName(void *prph);
void BTPeripheralDidModifyServices(void *prph, struct obj_arr *inv_svcs);
void BTPeripheralManagerDidUpdateState(void *pmgr);
void BTPeripheralManagerWillRestoreState(void *pmgr, struct pmgr_restore_opts *opts);
void BTPeripheralManagerDidAddService(void *pmgr, void *svc, struct bt_error *err);
void BTPeripheralManagerDidStartAdvertising(void *pmgr, struct bt_error *err);
void BTPeripheralManagerCentralDidSubscribe(void *pmgr, void *cent, void *chr);
void BTPeripheralManagerCentralDidUnsubscribe(void *pmgr, void *cent, void *chr);
void BTPeripheralManagerIsReadyToUpdateSubscribers(void *pmgr);
void BTPeripheralManagerDidReceiveReadRequest(void *pmgr, void *req);
void BTPeripheralManagerDidReceiveWriteRequests(void *pmgr, struct obj_arr *oa);
extern dispatch_queue_t bt_queue;
extern BTDlg *bt_dlg;
#endif

View File

@ -1,60 +0,0 @@
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
#import "bt.h"
dispatch_queue_t bt_queue;
static bool bt_loop_active;
/**
* Universal delegate. All callbacks get funnelled through this object before
* being translated to the appropriate Go calls.
*/
BTDlg *bt_dlg;
/**
* Starts a thread that processes CoreBluetooth events from the BT queue.
*
* @return false if the thread was already started;
* true if this call started a new thread.
*/
bool
bt_start()
{
if (bt_loop_active) {
return false;
}
bt_loop_active = true;
dispatch_async(dispatch_get_main_queue(), ^{
NSRunLoop *rl;
rl = [NSRunLoop currentRunLoop];
bool done;
do {
done = [rl runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
} while (bt_loop_active && !done);
});
return true;
}
void
bt_stop()
{
bt_loop_active = false;
}
void
bt_init()
{
// XXX: I have no idea why a separate queue is required here. When I
// attempt to use the default queue, the run loop does not receive any
// events.
if (bt_queue == NULL) {
bt_queue = dispatch_queue_create("bt_queue", NULL);
}
bt_dlg = [[BTDlg alloc] init];
[bt_dlg retain];
}

View File

@ -1,444 +0,0 @@
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
#import "bt.h"
@implementation BTDlg
- (id)
init
{
self = [super init];
if (self == nil) {
return nil;
}
return self;
}
/**
* Called when the central manager successfully connects to a peripheral.
*/
- (void)
centralManager:(CBCentralManager *)cm
didConnectPeripheral:(CBPeripheral *)prph
{
prph.delegate = self;
BTCentralManagerDidConnectPeripheral(cm, prph);
}
/**
* Called when a connection to a preipheral is terminated.
*/
- (void)
centralManager:(CBCentralManager *)cm
didDisconnectPeripheral:(CBPeripheral *)prph
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTCentralManagerDidDisconnectPeripheral(cm, prph, &err);
}
/**
* Called when the central manager fails to connect to a peripheral.
*/
- (void)
centralManager:(CBCentralManager *)cm
didFailToConnectPeripheral:(CBPeripheral *)prph
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTCentralManagerDidFailToConnectPeripheral(cm, prph, &err);
}
// macOS 10.15+
#if 0
- (void)
centralManager:(CBCentralManager *)cm
connectionEventDidOccur:(CBConnectionEvent)event
forPeripheral:(CBPeripheral *)prph
{
BTCentralManagerConnectionEventDidOccur(cm, event, prph);
}
#endif
/**
* Called when the central manager discovers a peripheral while scanning for
* devices.
*/
- (void)
centralManager:(CBCentralManager *)cm
didDiscoverPeripheral:(CBPeripheral *)prph
advertisementData:(NSDictionary *)advData
RSSI:(NSNumber *)RSSI
{
struct adv_fields af = {0};
af.name = dict_string(advData, CBAdvertisementDataLocalNameKey);
af.mfg_data = dict_bytes(advData, CBAdvertisementDataManufacturerDataKey);
af.pwr_lvl = dict_int(advData, CBAdvertisementDataTxPowerLevelKey, ADV_FIELDS_PWR_LVL_NONE);
af.connectable = dict_int(advData, CBAdvertisementDataIsConnectable, ADV_FIELDS_CONNECTABLE_NONE);
const NSArray *arr = [advData objectForKey:CBAdvertisementDataServiceUUIDsKey];
const char *svc_uuids[[arr count]];
for (int i = 0; i < [arr count]; i++) {
const CBUUID *uuid = [arr objectAtIndex:i];
svc_uuids[i] = [[uuid UUIDString] UTF8String];
}
af.svc_uuids = (struct string_arr) {
.strings = svc_uuids,
.count = [arr count],
};
const NSDictionary *dict = [advData objectForKey:CBAdvertisementDataServiceDataKey];
const NSArray *keys = [dict allKeys];
const char *svc_data_uuids[[keys count]];
struct byte_arr svc_data_values[[keys count]];
for (int i = 0; i < [keys count]; i++) {
const CBUUID *uuid = [keys objectAtIndex:i];
svc_data_uuids[i] = [[uuid UUIDString] UTF8String];
const NSData *data = [dict objectForKey:uuid];
svc_data_values[i].data = [data bytes];
svc_data_values[i].length = [data length];
}
af.svc_data_uuids = (struct string_arr) {
.strings = svc_data_uuids,
.count = [keys count],
};
af.svc_data_values = svc_data_values;
prph.delegate = self;
[prph retain];
BTCentralManagerDidDiscoverPeripheral(cm, prph, &af, [RSSI intValue]);
}
/**
* Called whenever the central manager's state is updated.
*/
- (void)
centralManagerDidUpdateState:(CBCentralManager *)cm
{
BTCentralManagerDidUpdateState(cm);
}
/**
* Called when the central manager is about to restore its state (as requested
* by the application).
*/
- (void)
centralManager:(CBCentralManager *)cm
willRestoreState:(NSDictionary<NSString *,id> *)dict
{
struct cmgr_restore_opts opts = {0};
const NSArray *prphs = [dict objectForKey:CBCentralManagerRestoredStatePeripheralsKey];
opts.prphs = nsarray_to_obj_arr(prphs);
const NSArray *uuids = [dict objectForKey:CBCentralManagerRestoredStateScanServicesKey];
opts.scan_svcs = cbuuids_to_strs(uuids);
struct scan_opts scan_opts = {0};
const NSDictionary *scan_dict = [dict objectForKey:CBCentralManagerRestoredStateScanOptionsKey];
if (scan_dict != nil && [scan_dict count] > 0) {
opts.scan_opts = &scan_opts;
NSNumber *dups = [scan_dict objectForKey:CBCentralManagerScanOptionAllowDuplicatesKey];
if (dups != nil && [dups boolValue]) {
opts.scan_opts->allow_dups = true;
}
NSArray *sol_uuids = [scan_dict objectForKey:CBCentralManagerScanOptionSolicitedServiceUUIDsKey];
opts.scan_opts->sol_svc_uuids = cbuuids_to_strs(sol_uuids);
}
BTCentralManagerWillRestoreState(cm, &opts);
free(scan_opts.sol_svc_uuids.strings);
free(opts.scan_svcs.strings);
free(opts.prphs.objs);
}
/**
* Called when the central manager successfully discovers services on a
* peripheral.
*/
- (void) peripheral:(CBPeripheral *)prph
didDiscoverServices:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTPeripheralDidDiscoverServices(prph, &err);
}
/**
* Called when the central manager successfully discovers included services of
* a peripheral's primary service.
*/
- (void) peripheral:(CBPeripheral *)prph
didDiscoverIncludedServicesForService:(CBService *)svc
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTPeripheralDidDiscoverIncludedServices(prph, svc, &err);
}
/**
* Called when the central manager successfully discovers characteristics of a
* peripheral's service.
*/
- (void)
peripheral:(CBPeripheral *)prph
didDiscoverCharacteristicsForService:(CBService *)svc
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTPeripheralDidDiscoverCharacteristics(prph, svc, &err);
}
/**
* Called when the central manager successfully discovers descriptors of a
* peripheral's characteristic.
*/
- (void)
peripheral:(CBPeripheral *)prph
didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)chr
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTPeripheralDidDiscoverDescriptors(prph, chr, &err);
}
/**
* Called when a connected peripheral communicates a characteristic's value
* (via read response, notification, or indication).
*/
- (void)
peripheral:(CBPeripheral *)prph
didUpdateValueForCharacteristic:(CBCharacteristic *)chr
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTPeripheralDidUpdateValueForCharacteristic(prph, chr, &err);
}
/**
* Called when a connected peripheral communicates a descriptors's value
* (via read response).
*/
- (void)
peripheral:(CBPeripheral *)prph
didUpdateValueForDescriptor:(CBDescriptor *)dsc
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTPeripheralDidUpdateValueForDescriptor(prph, dsc, &err);
}
/**
* Called when a connected peripheral responds to a Characteristic Write
* Request.
*/
- (void)
peripheral:(CBPeripheral *)prph
didWriteValueForCharacteristic:(CBCharacteristic *)chr
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTPeripheralDidWriteValueForCharacteristic(prph, chr, &err);
}
/**
* Called when a connected peripheral responds to a Descriptor Write Request.
*/
- (void)
peripheral:(CBPeripheral *)prph
didWriteValueForDescriptor:(CBDescriptor *)dsc
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTPeripheralDidWriteValueForDescriptor(prph, dsc, &err);
}
/**
* Called when a previously unsuccessful Write Without Response request can be
* retried.
*/
- (void)
peripheralIsReadyToSendWriteWithoutResponse:(CBPeripheral *)prph
{
BTPeripheralIsReadyToSendWriteWithoutResponse(prph);
}
/**
* Called when we (un)subscribe to a connected peripheral's characteristic.
*/
- (void)
peripheral:(CBPeripheral *)prph
didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)chr
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTPeripheralDidUpdateNotificationState(prph, chr, &err);
}
/**
* Called when we read a connected peripheral's RSSI.
*/
- (void)
peripheral:(CBPeripheral *)prph
didReadRSSI:(NSNumber *)RSSI
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTPeripheralDidReadRSSI(prph, [RSSI intValue], &err);
}
/**
* Called when a connected peripheral changes its name.
*/
- (void)
peripheralDidUpdateName:(CBPeripheral *)prph
{
BTPeripheralDidUpdateName(prph);
}
/**
* Called when a connected peripheral changes its set of services.
*/
- (void)
peripheral:(CBPeripheral *)prph
didModifyServices:(NSArray<CBService *> *)invSvcs
{
struct obj_arr oa = nsarray_to_obj_arr(invSvcs);
BTPeripheralDidModifyServices(prph, &oa);
free(oa.objs);
}
/**
* Called whenever the peripheral manager's state is updated.
*/
- (void)
peripheralManagerDidUpdateState:(CBPeripheralManager *)pm
{
BTPeripheralManagerDidUpdateState(pm);
}
/**
* Called when the peripheral manager is about to restore its state (as
* requested by the application).
*/
- (void)
peripheralManager:(CBPeripheralManager *)pmgr
willRestoreState:(NSDictionary<NSString *,id> *)dict
{
struct pmgr_restore_opts opts = {0};
const NSArray *svcs = [dict objectForKey:CBPeripheralManagerRestoredStateServicesKey];
opts.svcs = nsarray_to_obj_arr(svcs);
struct adv_data adv_data = {0};
const NSDictionary *ad_dict = [dict objectForKey:CBPeripheralManagerRestoredStateAdvertisementDataKey];
if (ad_dict != nil && [dict count] > 0) {
opts.adv_data = &adv_data;
NSString *nss = [ad_dict objectForKey:CBAdvertisementDataLocalNameKey];
if (nss != nil) {
adv_data.name = [nss UTF8String];
}
NSArray *nsa = [ad_dict objectForKey:CBAdvertisementDataServiceUUIDsKey];
if (nsa != nil) {
adv_data.svc_uuids = cbuuids_to_strs(nsa);
}
}
BTPeripheralManagerWillRestoreState(pmgr, &opts);
free(adv_data.svc_uuids.strings);
free(opts.svcs.objs);
}
/**
* Called when an attempt to register a service has completed.
*/
- (void)
peripheralManager:(CBPeripheralManager *)pmgr
didAddService:(CBService *)svc
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTPeripheralManagerDidAddService(pmgr, svc, &err);
}
/**
* Called when we start advertising or fail to advertise.
*/
- (void)
peripheralManagerDidStartAdvertising:(CBPeripheralManager *)pmgr
error:(NSError *)nserr
{
struct bt_error err = nserror_to_bt_error(nserr);
BTPeripheralManagerDidStartAdvertising(pmgr, &err);
}
/**
* Called when a connected central has subscribed to one of our
* characteristics.
*/
- (void)
peripheralManager:(CBPeripheralManager *)pmgr
central:(CBCentral *)cent
didSubscribeToCharacteristic:(CBCharacteristic *)chr
{
BTPeripheralManagerCentralDidSubscribe(pmgr, cent, chr);
}
/**
* Called when a connected central has unsubscribed from one of our
* characteristics.
*/
- (void)
peripheralManager:(CBPeripheralManager *)pmgr
central:(CBCentral *)cent
didUnsubscribeFromCharacteristic:(CBCharacteristic *)chr
{
BTPeripheralManagerCentralDidUnsubscribe(pmgr, cent, chr);
}
/**
* Called when a previous unsuccessful attempt to send notifications can be
* retried.
*/
- (void)
peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)pmgr
{
BTPeripheralManagerIsReadyToUpdateSubscribers(pmgr);
}
/**
* Called when a connected cerntral has sent us a read request.
*/
- (void)
peripheralManager:(CBPeripheralManager *)pmgr
didReceiveReadRequest:(CBATTRequest *)req
{
BTPeripheralManagerDidReceiveReadRequest(pmgr, req);
}
/**
* Called when connected cerntrals have sent us write requests.
*/
- (void)
peripheralManager:(CBPeripheralManager *)pmgr
didReceiveWriteRequests:(NSArray *)reqs
{
struct obj_arr oa = nsarray_to_obj_arr(reqs);
BTPeripheralManagerDidReceiveWriteRequests(pmgr, &oa);
free(oa.objs);
}
@end

View File

@ -1,406 +0,0 @@
package cbgo
// CBHandlers: Go handlers for asynchronous CoreBluetooth callbacks.
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
import (
"unsafe"
)
//export BTCentralManagerDidConnectPeripheral
func BTCentralManagerDidConnectPeripheral(cmgr unsafe.Pointer, prph unsafe.Pointer) {
btlog.Debugf("CentralManagerDidConnectPeripheral: cmgr=%v prph=%v", cmgr, prph)
dlg := findCentralManagerDlg(cmgr)
if dlg != nil {
dlg.DidConnectPeripheral(CentralManager{cmgr}, Peripheral{prph})
}
}
//export BTCentralManagerDidFailToConnectPeripheral
func BTCentralManagerDidFailToConnectPeripheral(cmgr unsafe.Pointer, prph unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("CentralManagerDidFailToConnectPeripheral: cmgr=%v prph=%v err=%v", cmgr, prph, nserr)
dlg := findCentralManagerDlg(cmgr)
if dlg != nil {
dlg.DidFailToConnectPeripheral(CentralManager{cmgr}, Peripheral{prph}, nserr)
}
}
//export BTCentralManagerDidDisconnectPeripheral
func BTCentralManagerDidDisconnectPeripheral(cmgr unsafe.Pointer, prph unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("CentralManagerDidDisconnectPeripheral: cmgr=%v prph=%v err=%v", cmgr, prph, nserr)
dlg := findCentralManagerDlg(cmgr)
if dlg != nil {
dlg.DidDisconnectPeripheral(CentralManager{cmgr}, Peripheral{prph}, nserr)
}
}
// macOS 10.15+
/*
//export BTCentralManagerConnectionEventDidOccur
func BTCentralManagerConnectionEventDidOccur(cmgr unsafe.Pointer, event C.int, prph unsafe.Pointer) {
dlg := findCentralManagerDlg(cmgr)
if dlg == nil {
return
}
dlg.ConnectionEventDidOccur(CentralManager{cmgr}, ConnectionEvent(event), Peripheral{prph})
}
*/
//export BTCentralManagerDidDiscoverPeripheral
func BTCentralManagerDidDiscoverPeripheral(cmgr unsafe.Pointer, prph unsafe.Pointer, advData *C.struct_adv_fields,
rssi C.int) {
af := AdvFields{}
af.LocalName = C.GoString(advData.name)
af.ManufacturerData = byteArrToByteSlice(&advData.mfg_data)
if advData.pwr_lvl != C.ADV_FIELDS_PWR_LVL_NONE {
i := int(advData.pwr_lvl)
af.TxPowerLevel = &i
}
if advData.connectable != C.ADV_FIELDS_CONNECTABLE_NONE {
b := advData.connectable != 0
af.Connectable = &b
}
af.ServiceUUIDs = mustStrArrToUUIDs(&advData.svc_uuids)
svcDataUUIDs := mustStrArrToUUIDs(&advData.svc_data_uuids)
for i, u := range svcDataUUIDs {
elemPtr := getArrElemAddr(unsafe.Pointer(advData.svc_data_values), unsafe.Sizeof(*advData.svc_data_values), i)
elem := (*C.struct_byte_arr)(elemPtr)
af.ServiceData = append(af.ServiceData, AdvServiceData{
UUID: u,
Data: byteArrToByteSlice(elem),
})
}
btlog.Debugf("CentralManagerDidDiscoverPeripheral: cmgr=%v prph=%v af=%+v rssi=%v", cmgr, prph, af, rssi)
dlg := findCentralManagerDlg(cmgr)
if dlg != nil {
dlg.DidDiscoverPeripheral(CentralManager{cmgr}, Peripheral{prph}, af, int(rssi))
}
}
//export BTCentralManagerDidUpdateState
func BTCentralManagerDidUpdateState(cmgr unsafe.Pointer) {
btlog.Debugf("CentralManagerDidUpdateState: cmgr=%v", cmgr)
dlg := findCentralManagerDlg(cmgr)
if dlg != nil {
dlg.CentralManagerDidUpdateState(CentralManager{cmgr})
}
}
//export BTCentralManagerWillRestoreState
func BTCentralManagerWillRestoreState(cmgr unsafe.Pointer, opts *C.struct_cmgr_restore_opts) {
ropts := CentralManagerRestoreOpts{}
ropts.Peripherals = make([]Peripheral, opts.prphs.count)
for i, _ := range ropts.Peripherals {
ropts.Peripherals[i].ptr = getObjArrElem(&opts.prphs, i)
}
ropts.ScanServices = mustStrArrToUUIDs(&opts.scan_svcs)
if opts.scan_opts != nil {
ropts.CentralManagerScanOpts = &CentralManagerScanOpts{
AllowDuplicates: bool(opts.scan_opts.allow_dups),
SolicitedServiceUUIDs: mustStrArrToUUIDs(&opts.scan_opts.sol_svc_uuids),
}
}
btlog.Debugf("CentralManagerWillRestoreState: cmgr=%v opts=%+v", cmgr, ropts)
dlg := findCentralManagerDlg(cmgr)
if dlg != nil {
dlg.CentralManagerWillRestoreState(CentralManager{cmgr}, ropts)
}
}
//export BTPeripheralDidDiscoverServices
func BTPeripheralDidDiscoverServices(prph unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("PeripheralDidDiscoverServices: prph=%v err=%v", prph, nserr)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.DidDiscoverServices(Peripheral{prph}, nserr)
}
}
//export BTPeripheralDidDiscoverIncludedServices
func BTPeripheralDidDiscoverIncludedServices(prph unsafe.Pointer, svc unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("PeripheralDidDiscoverIncludedServices: prph=%v svc=%v err=%v", prph, svc, nserr)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.DidDiscoverIncludedServices(Peripheral{prph}, Service{svc}, nserr)
}
}
//export BTPeripheralDidDiscoverCharacteristics
func BTPeripheralDidDiscoverCharacteristics(prph unsafe.Pointer, svc unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("PeripheralDidDiscoverCharacteristics: prph=%v svc=%v err=%v", prph, svc, nserr)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.DidDiscoverCharacteristics(Peripheral{prph}, Service{svc}, nserr)
}
}
//export BTPeripheralDidDiscoverDescriptors
func BTPeripheralDidDiscoverDescriptors(prph unsafe.Pointer, chr unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("PeripheralDidDiscoverDescriptors: prph=%v chr=%v err=%v", prph, chr, nserr)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.DidDiscoverDescriptors(Peripheral{prph}, Characteristic{chr}, nserr)
}
}
//export BTPeripheralDidUpdateValueForCharacteristic
func BTPeripheralDidUpdateValueForCharacteristic(prph unsafe.Pointer, chr unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("PeripheralDidUpdateValueForCharacteristic: prph=%v chr=%v err=%v", prph, chr, nserr)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.DidUpdateValueForCharacteristic(Peripheral{prph}, Characteristic{chr}, nserr)
}
}
//export BTPeripheralDidUpdateValueForDescriptor
func BTPeripheralDidUpdateValueForDescriptor(prph unsafe.Pointer, dsc unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("PeripheralDidUpdateValueForDescriptor: prph=%v dsc=%v err=%v", prph, dsc, nserr)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.DidUpdateValueForDescriptor(Peripheral{prph}, Descriptor{dsc}, nserr)
}
}
//export BTPeripheralDidWriteValueForCharacteristic
func BTPeripheralDidWriteValueForCharacteristic(prph unsafe.Pointer, chr unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("PeripheralDidWriteValueForCharacteristic: prph=%v chr=%v err=%v", prph, chr, nserr)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.DidWriteValueForCharacteristic(Peripheral{prph}, Characteristic{chr}, nserr)
}
}
//export BTPeripheralDidWriteValueForDescriptor
func BTPeripheralDidWriteValueForDescriptor(prph unsafe.Pointer, dsc unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("PeripheralDidWriteValueForDescriptor: prph=%v dsc=%v err=%v", prph, dsc, nserr)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.DidWriteValueForDescriptor(Peripheral{prph}, Descriptor{dsc}, nserr)
}
}
//export BTPeripheralIsReadyToSendWriteWithoutResponse
func BTPeripheralIsReadyToSendWriteWithoutResponse(prph unsafe.Pointer) {
btlog.Debugf("PeripheralIsReadyToSendWriteWithoutResponse: prph=%v", prph)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.IsReadyToSendWriteWithoutResponse(Peripheral{prph})
}
}
//export BTPeripheralDidUpdateNotificationState
func BTPeripheralDidUpdateNotificationState(prph unsafe.Pointer, chr unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("PeripheralDidUpdateNotificationState: prph=%v chr=%v err=%v", prph, chr, nserr)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.DidUpdateNotificationState(Peripheral{prph}, Characteristic{chr}, nserr)
}
}
//export BTPeripheralDidReadRSSI
func BTPeripheralDidReadRSSI(prph unsafe.Pointer, rssi C.int, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("PeripheralDidReadRSSI: prph=%v rssi=%v err=%v", prph, rssi, nserr)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.DidReadRSSI(Peripheral{prph}, int(rssi), nserr)
}
}
//export BTPeripheralDidUpdateName
func BTPeripheralDidUpdateName(prph unsafe.Pointer) {
btlog.Debugf("PeripheralDidUpdateName: prph=%v", prph)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.DidUpdateName(Peripheral{prph})
}
}
//export BTPeripheralDidModifyServices
func BTPeripheralDidModifyServices(prph unsafe.Pointer, inv_svcs *C.struct_obj_arr) {
svcs := make([]Service, inv_svcs.count)
for i, _ := range svcs {
elem := getObjArrElem(inv_svcs, i)
svc := Service{elem}
svcs = append(svcs, svc)
}
btlog.Debugf("PeripheralDidModifyServices: prph=%v inv_svcs=%+v", prph, svcs)
dlg := findPeripheralDlg(prph)
if dlg != nil {
dlg.DidModifyServices(Peripheral{prph}, svcs)
}
}
//export BTPeripheralManagerDidUpdateState
func BTPeripheralManagerDidUpdateState(pmgr unsafe.Pointer) {
btlog.Debugf("PeripheralManagerDidUpdateState: pmgr=%v", pmgr)
dlg := findPeripheralManagerDlg(pmgr)
if dlg != nil {
dlg.PeripheralManagerDidUpdateState(PeripheralManager{pmgr})
}
}
//export BTPeripheralManagerWillRestoreState
func BTPeripheralManagerWillRestoreState(pmgr unsafe.Pointer, opts *C.struct_pmgr_restore_opts) {
ropts := PeripheralManagerRestoreOpts{}
if opts.svcs.count > 0 {
ropts.Services = make([]MutableService, opts.svcs.count)
for i, _ := range ropts.Services {
ropts.Services[i] = MutableService{getObjArrElem(&opts.svcs, i)}
}
}
if opts.adv_data != nil {
ropts.AdvertisementData = &AdvData{
LocalName: C.GoString(opts.adv_data.name),
ServiceUUIDs: mustStrArrToUUIDs(&opts.adv_data.svc_uuids),
}
}
btlog.Debugf("PeripheralManagerWillRestoreState: pmgr=%v opts=%+v", pmgr, ropts)
dlg := findPeripheralManagerDlg(pmgr)
if dlg != nil {
dlg.PeripheralManagerWillRestoreState(PeripheralManager{pmgr}, ropts)
}
}
//export BTPeripheralManagerDidAddService
func BTPeripheralManagerDidAddService(pmgr unsafe.Pointer, svc unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("PeripheralManagerDidAddService: pmgr=%v err=%v", pmgr, nserr)
dlg := findPeripheralManagerDlg(pmgr)
if dlg != nil {
dlg.DidAddService(PeripheralManager{pmgr}, Service{svc}, nserr)
}
}
//export BTPeripheralManagerDidStartAdvertising
func BTPeripheralManagerDidStartAdvertising(pmgr unsafe.Pointer, err *C.struct_bt_error) {
nserr := btErrorToNSError(err)
btlog.Debugf("PeripheralManagerDidStartAdvertising: pmgr=%v err=%+v", pmgr, nserr)
dlg := findPeripheralManagerDlg(pmgr)
if dlg != nil {
dlg.DidStartAdvertising(PeripheralManager{pmgr}, nserr)
}
}
//export BTPeripheralManagerCentralDidSubscribe
func BTPeripheralManagerCentralDidSubscribe(pmgr unsafe.Pointer, cent unsafe.Pointer, chr unsafe.Pointer) {
btlog.Debugf("PeripheralManagerCentralDidSubscribe: pmgr=%v cent=%v chr=%v", pmgr, cent, chr)
dlg := findPeripheralManagerDlg(pmgr)
if dlg != nil {
dlg.CentralDidSubscribe(PeripheralManager{pmgr}, Central{cent}, Characteristic{chr})
}
}
//export BTPeripheralManagerCentralDidUnsubscribe
func BTPeripheralManagerCentralDidUnsubscribe(pmgr unsafe.Pointer, cent unsafe.Pointer, chr unsafe.Pointer) {
btlog.Debugf("PeripheralManagerCentralDidUnsubscribe: pmgr=%v cent=%v chr=%v", pmgr, cent, chr)
dlg := findPeripheralManagerDlg(pmgr)
if dlg != nil {
dlg.CentralDidUnsubscribe(PeripheralManager{pmgr}, Central{cent}, Characteristic{chr})
}
}
//export BTPeripheralManagerIsReadyToUpdateSubscribers
func BTPeripheralManagerIsReadyToUpdateSubscribers(pmgr unsafe.Pointer) {
btlog.Debugf("PeripheralManagerIsReadyToUpdateSubscribers: pmgr=%v")
dlg := findPeripheralManagerDlg(pmgr)
if dlg != nil {
dlg.IsReadyToUpdateSubscribers(PeripheralManager{pmgr})
}
}
//export BTPeripheralManagerDidReceiveReadRequest
func BTPeripheralManagerDidReceiveReadRequest(pmgr unsafe.Pointer, req unsafe.Pointer) {
btlog.Debugf("PeripheralManagerDidReceiveReadRequest: pmgr=%v req=%+v", pmgr, req)
dlg := findPeripheralManagerDlg(pmgr)
if dlg != nil {
dlg.DidReceiveReadRequest(PeripheralManager{pmgr}, ATTRequest{req})
}
}
//export BTPeripheralManagerDidReceiveWriteRequests
func BTPeripheralManagerDidReceiveWriteRequests(pmgr unsafe.Pointer, oa *C.struct_obj_arr) {
reqs := make([]ATTRequest, oa.count)
for i, _ := range reqs {
ptr := getObjArrElem(oa, i)
reqs[i] = ATTRequest{ptr}
}
btlog.Debugf("PeripheralManagerDidReceiveWriteRequests: pmgr=%v reqs=%v", pmgr, reqs)
dlg := findPeripheralManagerDlg(pmgr)
if dlg != nil {
dlg.DidReceiveWriteRequests(PeripheralManager{pmgr}, reqs)
}
}

View File

@ -1,25 +0,0 @@
package cbgo
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
import "unsafe"
// Central: https://developer.apple.com/documentation/corebluetooth/cbcentral
type Central struct {
ptr unsafe.Pointer
}
// Identifier: https://developer.apple.com/documentation/corebluetooth/cbpeer/1620687-identifier
func (c Central) Identifier() UUID {
cstr := C.cb_peer_identifier(c.ptr)
return MustParseUUID(C.GoString(cstr))
}
// MaximumUpdateValueLength: https://developer.apple.com/documentation/corebluetooth/cbcentral/1408800-maximumupdatevaluelength
func (c Central) MaximumUpdateValueLength() int {
return int(C.cb_cent_maximum_update_len(c.ptr))
}

View File

@ -1,185 +0,0 @@
package cbgo
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
import (
"unsafe"
)
// CentralManagerRestoreOpts: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/central_manager_state_restoration_options
type CentralManagerRestoreOpts struct {
Peripherals []Peripheral
ScanServices []UUID
CentralManagerScanOpts *CentralManagerScanOpts // nil if none
}
// CentralManagerScanOpts: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/peripheral_scanning_options
type CentralManagerScanOpts struct {
AllowDuplicates bool
SolicitedServiceUUIDs []UUID
}
// DfltCentralManagerConnectOpts is the set of options that gets used when nil
// is passed to `Connect()`.
var DfltCentralManagerConnectOpts = CentralManagerConnectOpts{
NotifyOnConnection: true,
NotifyOnDisconnection: true,
NotifyOnNotification: true,
}
// DfltCentralManagerScanOpts is the set of options that gets used when nil is
// passed to `Scan()`.
var DfltCentralManagerScanOpts = CentralManagerScanOpts{}
// CentralManagerConnectOpts: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/peripheral_connection_options
type CentralManagerConnectOpts struct {
NotifyOnConnection bool
NotifyOnDisconnection bool
NotifyOnNotification bool
EnableTransportBridging bool
RequiresANCS bool
StartDelay int
}
// CentralManager: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager?language=objc
type CentralManager struct {
ptr unsafe.Pointer
}
var cmgrPtrMap = newPtrMap()
func findCentralManagerDlg(ptr unsafe.Pointer) CentralManagerDelegate {
itf := cmgrPtrMap.find(ptr)
if itf == nil {
return nil
}
return itf.(CentralManagerDelegate)
}
// NewCentralManager creates a central manager. Specify a nil `opts` value for
// defaults. Don't forget to call `SetDelegate()` afterwards!
func NewCentralManager(opts *ManagerOpts) CentralManager {
if opts == nil {
opts = &DfltManagerOpts
}
pwrAlert := C.bool(opts.ShowPowerAlert)
restoreID := (*C.char)(nil)
if opts.RestoreIdentifier != "" {
restoreID = C.CString(opts.RestoreIdentifier)
defer C.free(unsafe.Pointer(restoreID))
}
return CentralManager{
ptr: unsafe.Pointer(C.cb_alloc_cmgr(pwrAlert, restoreID)),
}
}
// SetDelegate configures a receiver for a central manager's asynchronous
// callbacks.
func (cm CentralManager) SetDelegate(d CentralManagerDelegate) {
if d != nil {
cmgrPtrMap.add(cm.ptr, d)
}
C.cb_cmgr_set_delegate(cm.ptr, C.bool(d != nil))
}
// State: https://developer.apple.com/documentation/corebluetooth/cbmanager/1648600-state
func (cm CentralManager) State() ManagerState {
return ManagerState(C.cb_cmgr_state(cm.ptr))
}
// Connect: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/1518766-connectperipheral
func (cm CentralManager) Connect(prph Peripheral, opts *CentralManagerConnectOpts) {
if opts == nil {
opts = &DfltCentralManagerConnectOpts
}
copts := C.struct_connect_opts{
notify_on_connection: C.bool(opts.NotifyOnConnection),
notify_on_disconnection: C.bool(opts.NotifyOnDisconnection),
notify_on_notification: C.bool(opts.NotifyOnNotification),
enable_transport_bridging: C.bool(opts.EnableTransportBridging),
requires_ancs: C.bool(opts.RequiresANCS),
start_delay: C.int(opts.StartDelay),
}
C.cb_cmgr_connect(cm.ptr, prph.ptr, &copts)
}
// CancelConnect: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/1518952-cancelperipheralconnection
func (cm CentralManager) CancelConnect(prph Peripheral) {
C.cb_cmgr_cancel_connect(cm.ptr, prph.ptr)
}
// RetrieveConnectedPeripheralsWithServices: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/1518924-retrieveconnectedperipheralswith
func (cm CentralManager) RetrieveConnectedPeripheralsWithServices(uuids []UUID) []Peripheral {
strs := uuidsToStrArr(uuids)
defer freeStrArr(&strs)
var prphs []Peripheral
prphPtrs := C.cb_cmgr_retrieve_prphs_with_svcs(cm.ptr, &strs)
defer C.free(unsafe.Pointer(prphPtrs.objs))
for i := 0; i < int(prphPtrs.count); i++ {
ptr := getObjArrElem(&prphPtrs, i)
prphs = append(prphs, Peripheral{ptr})
}
return prphs
}
// RetrievePeripheralsWithIdentifiers: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/1519127-retrieveperipheralswithidentifie
func (cm CentralManager) RetrievePeripheralsWithIdentifiers(uuids []UUID) []Peripheral {
strs := uuidsToStrArr(uuids)
defer freeStrArr(&strs)
var prphs []Peripheral
prphPtrs := C.cb_cmgr_retrieve_prphs(cm.ptr, &strs)
defer C.free(unsafe.Pointer(prphPtrs.objs))
for i := 0; i < int(prphPtrs.count); i++ {
ptr := getObjArrElem(&prphPtrs, i)
prphs = append(prphs, Peripheral{ptr})
}
return prphs
}
// Scan: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/1518986-scanforperipheralswithservices
func (cm CentralManager) Scan(serviceUUIDs []UUID, opts *CentralManagerScanOpts) {
arrSvcUUIDs := uuidsToStrArr(serviceUUIDs)
defer freeStrArr(&arrSvcUUIDs)
if opts == nil {
opts = &DfltCentralManagerScanOpts
}
arrSolSvcUUIDs := uuidsToStrArr(opts.SolicitedServiceUUIDs)
defer freeStrArr(&arrSolSvcUUIDs)
copts := C.struct_scan_opts{
allow_dups: C.bool(opts.AllowDuplicates),
sol_svc_uuids: arrSolSvcUUIDs,
}
C.cb_cmgr_scan(cm.ptr, &arrSvcUUIDs, &copts)
}
// StopScan: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/1518984-stopscan
func (cm CentralManager) StopScan() {
C.cb_cmgr_stop_scan(cm.ptr)
}
// IsScanning: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/1620640-isscanning
func (cm CentralManager) IsScanning() bool {
return bool(C.cb_cmgr_is_scanning(cm.ptr))
}

View File

@ -1,41 +0,0 @@
package cbgo
// CentralManagerDelegate: https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate
type CentralManagerDelegate interface {
// DidConnectPeripheral: https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate/1518969-centralmanager
DidConnectPeripheral(cmgr CentralManager, prph Peripheral)
// DidDisconnectPeripheral: https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate/1518791-centralmanager
DidDisconnectPeripheral(cmgr CentralManager, prph Peripheral, err error)
// DidFailToConnectPeripheral: https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate/1518988-centralmanager
DidFailToConnectPeripheral(cmgr CentralManager, prph Peripheral, err error)
// DidDiscoverPeripheral: https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate/1518937-centralmanager
DidDiscoverPeripheral(cmgr CentralManager, prph Peripheral, advFields AdvFields, rssi int)
// CentralManagerDidUpdateState: https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate/1518888-centralmanagerdidupdatestate
CentralManagerDidUpdateState(cmgr CentralManager)
// CentralManagerWillRestoreState: https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate/1518819-centralmanager
CentralManagerWillRestoreState(cmgr CentralManager, opts CentralManagerRestoreOpts)
}
// CentralManagerDelegateBase implements the CentralManagerDelegate interface
// with stub functions. Embed this in your delegate type if you only want to
// define a subset of the CentralManagerDelegate interface.
type CentralManagerDelegateBase struct {
}
func (b *CentralManagerDelegateBase) DidConnectPeripheral(cmgr CentralManager, prph Peripheral) {
}
func (b *CentralManagerDelegateBase) DidFailToConnectPeripheral(cmgr CentralManager, prph Peripheral, err error) {
}
func (b *CentralManagerDelegateBase) DidDisconnectPeripheral(cmgr CentralManager, prph Peripheral, err error) {
}
func (b *CentralManagerDelegateBase) CentralManagerDidUpdateState(cmgr CentralManager) {
}
func (b *CentralManagerDelegateBase) CentralManagerWillRestoreState(cmgr CentralManager, opts CentralManagerRestoreOpts) {
}
func (b *CentralManagerDelegateBase) DidDiscoverPeripheral(cmgr CentralManager, prph Peripheral, advFields AdvFields, rssi int) {
}

View File

@ -1,80 +0,0 @@
package cbgo
import "unsafe"
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
// CharacteristicProperties: https://developer.apple.com/documentation/corebluetooth/cbcharacteristicproperties
type CharacteristicProperties int
const (
CharacteristicPropertyBroadcast = CharacteristicProperties(C.CBCharacteristicPropertyBroadcast)
CharacteristicPropertyRead = CharacteristicProperties(C.CBCharacteristicPropertyRead)
CharacteristicPropertyWriteWithoutResponse = CharacteristicProperties(C.CBCharacteristicPropertyWriteWithoutResponse)
CharacteristicPropertyWrite = CharacteristicProperties(C.CBCharacteristicPropertyWrite)
CharacteristicPropertyNotify = CharacteristicProperties(C.CBCharacteristicPropertyNotify)
CharacteristicPropertyIndicate = CharacteristicProperties(C.CBCharacteristicPropertyIndicate)
CharacteristicPropertyAuthenticatedSignedWrites = CharacteristicProperties(C.CBCharacteristicPropertyAuthenticatedSignedWrites)
CharacteristicPropertyExtendedProperties = CharacteristicProperties(C.CBCharacteristicPropertyExtendedProperties)
CharacteristicPropertyNotifyEncryptionRequired = CharacteristicProperties(C.CBCharacteristicPropertyNotifyEncryptionRequired)
CharacteristicPropertyIndicateEncryptionRequired = CharacteristicProperties(C.CBCharacteristicPropertyIndicateEncryptionRequired)
)
func chrWriteType(withRsp bool) C.int {
if withRsp {
return C.CBCharacteristicWriteWithResponse
} else {
return C.CBCharacteristicWriteWithoutResponse
}
}
// Characteristic: https://developer.apple.com/documentation/corebluetooth/cbcharacteristic
type Characteristic struct {
ptr unsafe.Pointer
}
// UUID: https://developer.apple.com/documentation/corebluetooth/cbattribute/1620638-uuid
func (c Characteristic) UUID() UUID {
cstr := C.cb_chr_uuid(c.ptr)
return MustParseUUID(C.GoString(cstr))
}
// Service: https://developer.apple.com/documentation/corebluetooth/cbcharacteristic/1518728-service
func (c Characteristic) Service() Service {
ptr := C.cb_chr_service(c.ptr)
return Service{ptr}
}
// Value: https://developer.apple.com/documentation/corebluetooth/cbcharacteristic/1518878-value
func (c Characteristic) Value() []byte {
ba := C.cb_chr_value(c.ptr)
return byteArrToByteSlice(&ba)
}
// Descriptors: https://developer.apple.com/documentation/corebluetooth/cbcharacteristic/1518957-descriptors
func (c Characteristic) Descriptors() []Descriptor {
oa := C.cb_chr_descriptors(c.ptr)
defer C.free(unsafe.Pointer(oa.objs))
dscs := make([]Descriptor, oa.count)
for i, _ := range dscs {
obj := getObjArrElem(&oa, i)
dscs[i] = Descriptor{ptr: obj}
}
return dscs
}
// Properties: https://developer.apple.com/documentation/corebluetooth/cbcharacteristic/1519010-properties
func (c Characteristic) Properties() CharacteristicProperties {
return CharacteristicProperties(C.cb_chr_properties(c.ptr))
}
// IsNotifying: https://developer.apple.com/documentation/corebluetooth/cbcharacteristic/1519057-isnotifying
func (c Characteristic) IsNotifying() bool {
return bool(C.cb_chr_is_notifying(c.ptr))
}

View File

@ -1,430 +0,0 @@
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
#import <CoreLocation/CoreLocation.h>
#import "bt.h"
// cmgr.m: C functions for interfacing with CoreBluetooth central
// functionality. This is necessary because Go code cannot execute some
// objective C constructs directly.
CBCentralManager *
cb_alloc_cmgr(bool pwr_alert, const char *restore_id)
{
// Ensure queue is initialized.
bt_init();
NSMutableDictionary *opts = [[NSMutableDictionary alloc] init];
[opts autorelease];
if (pwr_alert) {
[opts setObject:[NSNumber numberWithBool:pwr_alert]
forKey:CBCentralManagerOptionShowPowerAlertKey];
}
if (restore_id != NULL) {
[opts setObject:str_to_nsstring(restore_id)
forKey:CBCentralManagerOptionRestoreIdentifierKey];
}
CBCentralManager *cm = [[CBCentralManager alloc] initWithDelegate:bt_dlg
queue:bt_queue
options:opts];
[cm retain];
return cm;
}
void
cb_cmgr_set_delegate(void *cmgr, bool set)
{
BTDlg *del;
if (set) {
del = bt_dlg;
} else {
del = nil;
}
((CBCentralManager *)cmgr).delegate = del;
}
int
cb_cmgr_state(void *cmgr)
{
CBCentralManager *cm = cmgr;
return [cm state];
}
void
cb_cmgr_scan(void *cmgr, const struct string_arr *svc_uuids,
const struct scan_opts *opts)
{
NSArray *arr_svc_uuids = strs_to_cbuuids(svc_uuids);
[arr_svc_uuids autorelease];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict autorelease];
if (opts->allow_dups) {
[dict setObject:[NSNumber numberWithBool:YES]
forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
}
if (opts->sol_svc_uuids.count > 0) {
NSArray *arr_sol_svc_uuids = strs_to_cbuuids(&opts->sol_svc_uuids);
[arr_sol_svc_uuids autorelease];
[dict setObject:arr_sol_svc_uuids
forKey:CBCentralManagerScanOptionSolicitedServiceUUIDsKey];
}
CBCentralManager *cm = cmgr;
[cm scanForPeripheralsWithServices:arr_svc_uuids options:dict];
}
void
cb_cmgr_stop_scan(void *cmgr)
{
[(CBCentralManager *)cmgr stopScan];
}
bool
cb_cmgr_is_scanning(void *cmgr)
{
return ((CBCentralManager *)cmgr).isScanning;
}
void
cb_cmgr_connect(void *cmgr, void *prph, const struct connect_opts *opts)
{
CBCentralManager *cm = cmgr;
CBPeripheral *pr = prph;
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict autorelease];
if (opts->notify_on_connection) {
dict_set_bool(dict, CBConnectPeripheralOptionNotifyOnConnectionKey, true);
}
if (opts->notify_on_disconnection) {
dict_set_bool(dict, CBConnectPeripheralOptionNotifyOnDisconnectionKey, true);
}
if (opts->notify_on_notification) {
dict_set_bool(dict, CBConnectPeripheralOptionNotifyOnNotificationKey, true);
}
// XXX: These don't seem to be supported in all versions of macOS.
#if 0
if (opts->enable_transport_bridging) {
dict_set_bool(dict, CBConnectPeripheralOptionEnableTransportBridgingKey, true);
}
if (opts->requires_ancs) {
dict_set_bool(dict, CBConnectPeripheralOptionRequiresANCS, true);
}
if (opts->start_delay > 0) {
dict_set_int(dict, CBConnectPeripheralOptionStartDelayKey, opts->start_delay);
}
#endif
[cm connectPeripheral:pr options:dict];
}
void
cb_cmgr_cancel_connect(void *cmgr, void *prph)
{
CBCentralManager *cm = cmgr;
CBPeripheral *pr = prph;
[cm cancelPeripheralConnection:pr];
}
struct obj_arr
cb_cmgr_retrieve_prphs_with_svcs(void *cmgr, const struct string_arr *uuids)
{
CBCentralManager *cm = cmgr;
NSArray *cbuuids = strs_to_cbuuids(uuids);
NSArray *prphs = [cm retrieveConnectedPeripheralsWithServices:cbuuids];
if ([prphs count] <= 0) {
return (struct obj_arr) {0};
}
void **objs = malloc([prphs count] * sizeof *objs);
assert(objs != NULL);
for (int i = 0; i < [prphs count]; i++) {
objs[i] = [prphs objectAtIndex:i];
}
return (struct obj_arr) {
.objs = objs,
.count = [prphs count],
};
}
struct obj_arr
cb_cmgr_retrieve_prphs(void *cmgr, const struct string_arr *uuids)
{
CBCentralManager *cm = cmgr;
NSArray *nsuuids = strs_to_nsuuids(uuids);
NSArray *prphs = [cm retrievePeripheralsWithIdentifiers:nsuuids];
if ([prphs count] <= 0) {
return (struct obj_arr) {0};
}
void **objs = malloc([prphs count] * sizeof *objs);
assert(objs != NULL);
for (int i = 0; i < [prphs count]; i++) {
objs[i] = [prphs objectAtIndex:i];
}
return (struct obj_arr) {
.objs = objs,
.count = [prphs count],
};
}
const char *
cb_peer_identifier(void *peer)
{
NSUUID *uuid = [(CBPeer *)peer identifier];
return [[uuid UUIDString] UTF8String];
}
void
cb_prph_set_delegate(void *prph, bool set)
{
BTDlg *del;
if (set) {
del = bt_dlg;
} else {
del = nil;
}
((CBPeripheral *)prph).delegate = del;
}
const char *
cb_prph_name(void *prph)
{
NSString *nss = [(CBPeripheral *)prph name];
return [nss UTF8String];
}
struct obj_arr
cb_prph_services(void *prph)
{
NSArray *svcs = ((CBPeripheral *)prph).services;
return nsarray_to_obj_arr(svcs);
}
void
cb_prph_discover_svcs(void *prph, const struct string_arr *svc_uuid_strs)
{
NSArray *svc_uuids = strs_to_cbuuids(svc_uuid_strs);
[(CBPeripheral *)prph discoverServices:svc_uuids];
}
void
cb_prph_discover_included_svcs(void *prph, const struct string_arr *svc_uuid_strs, void *svc)
{
NSArray *svc_uuids = strs_to_cbuuids(svc_uuid_strs);
[(CBPeripheral *)prph discoverIncludedServices:svc_uuids forService:svc];
}
void
cb_prph_discover_chrs(void *prph, void *svc, const struct string_arr *chr_uuid_strs)
{
NSArray *chr_uuids = strs_to_cbuuids(chr_uuid_strs);
[(CBPeripheral *)prph discoverCharacteristics:chr_uuids forService:svc];
}
void
cb_prph_discover_dscs(void *prph, void *chr)
{
[(CBPeripheral *)prph discoverDescriptorsForCharacteristic:chr];
}
void
cb_prph_read_chr(void *prph, void *chr)
{
[(CBPeripheral *)prph readValueForCharacteristic:chr];
}
void
cb_prph_read_dsc(void *prph, void *dsc)
{
[(CBPeripheral *)prph readValueForDescriptor:dsc];
}
void
cb_prph_write_chr(void *prph, void *chr, struct byte_arr *value, int type)
{
NSData *nsd = byte_arr_to_nsdata(value);
[(CBPeripheral *)prph writeValue:nsd
forCharacteristic:chr
type:type];
}
void
cb_prph_write_dsc(void *prph, void *dsc, struct byte_arr *value)
{
NSData *nsd = byte_arr_to_nsdata(value);
[(CBPeripheral *)prph writeValue:nsd
forDescriptor:dsc];
}
int
cb_prph_max_write_len(void *prph, int type)
{
return [(CBPeripheral *)prph maximumWriteValueLengthForType:type];
}
void
cb_prph_set_notify(void *prph, bool enabled, void *chr)
{
[(CBPeripheral *)prph setNotifyValue:enabled forCharacteristic:chr];
}
int
cb_prph_state(void *prph)
{
return ((CBPeripheral *) prph).state;
}
bool
cb_prph_can_send_write_without_rsp(void *prph)
{
return ((CBPeripheral *)prph).canSendWriteWithoutResponse;
}
void
cb_prph_read_rssi(void *prph)
{
[(CBPeripheral *)prph readRSSI];
}
// error: 'openL2CAPChannel:' is unavailable: not available on macOS
#if 0
void
cb_prph_open_l2cap_channel(void *prph, uint16_t cid)
{
[(CBPeripheral *)prph openL2CAPChannel:cid];
}
#endif
// error: property 'ancsAuthorized' not found on object of type 'CBPeripheral *'
#if 0
bool
cb_prph_ancs_authorized(void *prph)
{
return ((CBPeripheral *)prph).ancsAuthorized;
}
#endif
const char *
cb_svc_uuid(void *svc)
{
CBUUID *cbuuid = ((CBService *)svc).UUID;
return [[cbuuid UUIDString] UTF8String];
}
void *
cb_svc_peripheral(void *svc)
{
return ((CBService *)svc).peripheral;
}
bool
cb_svc_is_primary(void *svc)
{
return ((CBService *)svc).isPrimary;
}
struct obj_arr
cb_svc_characteristics(void *svc)
{
NSArray *chrs = ((CBService *)svc).characteristics;
return nsarray_to_obj_arr(chrs);
}
struct obj_arr
cb_svc_included_svcs(void *svc)
{
NSArray *svcs = ((CBService *)svc).includedServices;
return nsarray_to_obj_arr(svcs);
}
const char *
cb_chr_uuid(void *chr)
{
CBUUID *cbuuid = ((CBCharacteristic *)chr).UUID;
return [[cbuuid UUIDString] UTF8String];
}
void *
cb_chr_service(void *chr)
{
return ((CBCharacteristic *)chr).service;
}
struct obj_arr
cb_chr_descriptors(void *chr)
{
NSArray *dscs = ((CBCharacteristic *)chr).descriptors;
return nsarray_to_obj_arr(dscs);
}
struct byte_arr
cb_chr_value(void *chr)
{
NSData *nsd = ((CBCharacteristic *)chr).value;
return nsdata_to_byte_arr(nsd);
}
int
cb_chr_properties(void *chr)
{
return ((CBCharacteristic *)chr).properties;
}
bool
cb_chr_is_notifying(void *chr)
{
return ((CBCharacteristic *)chr).isNotifying;
}
const char *
cb_dsc_uuid(void *dsc)
{
CBUUID *cbuuid = ((CBDescriptor *)dsc).UUID;
return [[cbuuid UUIDString] UTF8String];
}
void *
cb_dsc_characteristic(void *dsc)
{
return ((CBDescriptor *)dsc).characteristic;
}
struct byte_arr
cb_dsc_value(void *dsc)
{
id val = ((CBDescriptor *)dsc).value;
// `value` returns a different type depending on the descriptor being
// queried! Convert whatever got returned to a byte array.
if ([val isKindOfClass:[NSData class]]) {
return nsdata_to_byte_arr(val);
}
if ([val isKindOfClass:[NSString class]]) {
NSData *nsd = [val dataUsingEncoding:NSUTF8StringEncoding];
return nsdata_to_byte_arr(nsd);
}
// Unknown type.
return (struct byte_arr){0};
}

View File

@ -1,143 +0,0 @@
package cbgo
import (
"encoding/binary"
"encoding/hex"
"fmt"
"strconv"
)
const UUID16StringLength = 4
const UUID128StringLength = 36
// UUID is a 16-bit or 128-bit UUID.
type UUID []byte
func reverse(bs []byte) []byte {
c := make([]byte, len(bs))
for i, b := range bs {
c[len(c)-1-i] = b
}
return c
}
// UUID16 constructs a 16-bit UUID from a uint16.
func UUID16(i uint16) UUID {
b := make([]byte, 2)
binary.LittleEndian.PutUint16(b, i)
return UUID(b)
}
// UUID16 constructs a 128-bit UUID from a 16-element byte slice.
func UUID128(b []byte) (UUID, error) {
if len(b) != 16 {
return nil, fmt.Errorf("failed to construct UUID128: wrong length: have=%d want=16", len(b))
}
return UUID(b), nil
}
// ParseUUID16 parses a UUID string with the form:
// 1234
func ParseUUID16(s string) (UUID, error) {
if len(s) != UUID16StringLength {
return nil, fmt.Errorf("invalid UUID16: %s", s)
}
b, err := hex.DecodeString(s)
if err != nil {
return nil, fmt.Errorf("invald UUID16: %v", err)
}
return UUID(reverse(b)), nil
}
// ParseUUID128 parses a UUID string with the form:
// 01234567-89ab-cdef-0123-456789abcdef
func ParseUUID128(s string) (UUID, error) {
if len(s) != UUID128StringLength {
return nil, fmt.Errorf("invalid UUID128: %s", s)
}
b := make([]byte, 16)
off := 0
for i := 0; i < 36; {
switch i {
case 8, 13, 18, 23:
if s[i] != '-' {
return nil, fmt.Errorf("invalid UUID128: %s", s)
}
i++
default:
u64, err := strconv.ParseUint(s[i:i+2], 16, 8)
if err != nil {
return nil, fmt.Errorf("invalid UUID128: %s", s)
}
b[off] = byte(u64)
i += 2
off++
}
}
return UUID(reverse(b)), nil
}
// ParseUUID parses a string representing a 16-bit or 128-bit UUID.
func ParseUUID(s string) (UUID, error) {
switch len(s) {
case UUID16StringLength:
return ParseUUID16(s)
case UUID128StringLength:
return ParseUUID128(s)
default:
return nil, fmt.Errorf("invalid UUID string: %s", s)
}
}
// MustParseUUID is like ParseUUID except it panics on failure.
func MustParseUUID(s string) UUID {
uuid, err := ParseUUID(s)
if err != nil {
panic(err)
}
return uuid
}
// String retruns a CoreBluetooth-friendly string representation of a UUID.
func (u UUID) String() string {
b := reverse(u)
switch len(b) {
case 2:
return fmt.Sprintf("%x", []byte(b))
case 16:
s := fmt.Sprintf("%x", []byte(b))
// 01234567-89ab-cdef-0123-456789abcdef
return s[:8] + "-" + s[8:12] + "-" + s[12:16] + "-" + s[16:20] + "-" + s[20:]
default:
btlog.Errorf("invalid UUID: %s", hex.EncodeToString(u))
return ""
}
}
// NSError: https://developer.apple.com/documentation/foundation/nserror
type NSError struct {
msg string
code int
}
func (e *NSError) Message() string {
return e.msg
}
func (e *NSError) Code() int {
return e.code
}
func (e *NSError) Error() string {
return e.msg
}

View File

@ -1,173 +0,0 @@
package cbgo
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation -framework CoreBluetooth
#import "bt.h"
*/
import "C"
import (
"unsafe"
)
func mallocArr(numElems int, elemSize uintptr) unsafe.Pointer {
return C.malloc(C.size_t(numElems) * C.size_t(elemSize))
}
// getArrElemAddr retrieves the address of an element from a C array.
func getArrElemAddr(arr unsafe.Pointer, elemSize uintptr, idx int) unsafe.Pointer {
base := uintptr(arr)
off := uintptr(idx) * elemSize
cur := base + off
return unsafe.Pointer(cur)
}
// freeArrElems frees each element of a C-array of pointers.
func freeArrElems(arr unsafe.Pointer, elemSize uintptr, count int) {
for i := 0; i < count; i++ {
base := uintptr(arr)
off := uintptr(i) * elemSize
addr := base + off
pp := unsafe.Pointer(addr)
ptr := *(*unsafe.Pointer)(pp)
C.free(ptr)
}
}
func byteArrToByteSlice(byteArr *C.struct_byte_arr) []byte {
return C.GoBytes(unsafe.Pointer(byteArr.data), byteArr.length)
}
func byteSliceToByteArr(b []byte) C.struct_byte_arr {
if len(b) == 0 {
return C.struct_byte_arr{
data: nil,
length: 0,
}
} else {
return C.struct_byte_arr{
data: (*C.uint8_t)(C.CBytes(b)),
length: C.int(len(b)),
}
}
}
func stringArrToStringSlice(sa *C.struct_string_arr) []string {
ss := make([]string, sa.count)
for i, _ := range ss {
ss[i] = getStrArrElem(sa, i)
}
return ss
}
func stringSliceToArr(ss []string) C.struct_string_arr {
if len(ss) == 0 {
return C.struct_string_arr{}
}
ptr := mallocArr(len(ss), unsafe.Sizeof((*C.char)(nil)))
carr := (*[1<<30 - 1]*C.char)(ptr)
for i, s := range ss {
carr[i] = C.CString(s)
}
return C.struct_string_arr{
strings: (**C.char)(ptr),
count: C.int(len(ss)),
}
}
// getStrArrElem retrieves an element from a `struct string_arr` C object.
func getStrArrElem(sa *C.struct_string_arr, idx int) string {
elemSize := unsafe.Sizeof(*sa.strings)
ptr := getArrElemAddr(unsafe.Pointer(sa.strings), elemSize, idx)
cstr := *(**C.char)(ptr)
return C.GoString(cstr)
}
func uuidsToStrArr(uuids []UUID) C.struct_string_arr {
var ss []string
for _, u := range uuids {
ss = append(ss, u.String())
}
return stringSliceToArr(ss)
}
func strArrToUUIDs(sa *C.struct_string_arr) ([]UUID, error) {
if sa == nil || sa.count == 0 {
return nil, nil
}
uuids := make([]UUID, sa.count)
ss := stringArrToStringSlice(sa)
for i, s := range ss {
uuid, err := ParseUUID(s)
if err != nil {
return nil, err
}
uuids[i] = uuid
}
return uuids, nil
}
func mustStrArrToUUIDs(sa *C.struct_string_arr) []UUID {
uuids, err := strArrToUUIDs(sa)
if err != nil {
panic(err)
}
return uuids
}
func freeStrArr(sa *C.struct_string_arr) {
freeArrElems(unsafe.Pointer(sa.strings), unsafe.Sizeof(*sa.strings), int(sa.count))
C.free(unsafe.Pointer(sa.strings))
}
func btErrorToNSError(e *C.struct_bt_error) error {
if e == nil || e.msg == nil {
return nil
} else {
return &NSError{
msg: C.GoString(e.msg),
code: int(e.code),
}
}
}
func mallocObjArr(count int) C.struct_obj_arr {
if count <= 0 {
return C.struct_obj_arr{
objs: nil,
count: 0,
}
}
data := mallocArr(count, unsafe.Sizeof(unsafe.Pointer(nil)))
return C.struct_obj_arr{
objs: (*unsafe.Pointer)(data),
count: C.int(count),
}
}
// getStrArrElem retrieves an element from a `struct obj_arr` C object.
func getObjArrElem(oa *C.struct_obj_arr, idx int) unsafe.Pointer {
addr := getArrElemAddr(unsafe.Pointer(oa.objs), unsafe.Sizeof(*oa.objs), idx)
dptr := (*unsafe.Pointer)(addr)
return *dptr
}
// setStrArrElem assigns an element in a `struct obj_arr` C object.
func setObjArrElem(oa *C.struct_obj_arr, idx int, val unsafe.Pointer) {
addr := getArrElemAddr(unsafe.Pointer(oa.objs), unsafe.Sizeof(*oa.objs), idx)
dptr := (*unsafe.Pointer)(addr)
*dptr = val
}

View File

@ -1,32 +0,0 @@
package cbgo
import "unsafe"
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
// Descriptor: https://developer.apple.com/documentation/corebluetooth/cbdescriptor
type Descriptor struct {
ptr unsafe.Pointer
}
// UUID: https://developer.apple.com/documentation/corebluetooth/cbattribute/1620638-uuid
func (d Descriptor) UUID() UUID {
cstr := C.cb_dsc_uuid(d.ptr)
return MustParseUUID(C.GoString(cstr))
}
// Characteristic: https://developer.apple.com/documentation/corebluetooth/cbdescriptor/1519035-characteristic
func (d Descriptor) Characteristic() Characteristic {
ptr := C.cb_dsc_characteristic(d.ptr)
return Characteristic{ptr}
}
// Value: https://developer.apple.com/documentation/corebluetooth/cbdescriptor/1518778-value
func (d Descriptor) Value() []byte {
ba := C.cb_dsc_value(d.ptr)
return byteArrToByteSlice(&ba)
}

View File

@ -1,5 +0,0 @@
module github.com/JuulLabs-OSS/cbgo
go 1.14
require github.com/sirupsen/logrus v1.5.0

View File

@ -1,8 +0,0 @@
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@ -1,32 +0,0 @@
package cbgo
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
// ManagerState: https://developer.apple.com/documentation/corebluetooth/cbmanagerstate
type ManagerState int
const (
ManagerStatePoweredOff = ManagerState(C.CBManagerStatePoweredOff)
ManagerStatePoweredOn = ManagerState(C.CBManagerStatePoweredOn)
ManagerStateResetting = ManagerState(C.CBManagerStateResetting)
ManagerStateUnauthorized = ManagerState(C.CBManagerStateUnauthorized)
ManagerStateUnknown = ManagerState(C.CBManagerStateUnknown)
ManagerStateUnsupported = ManagerState(C.CBManagerStateUnsupported)
)
// ManagerOpts: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/central_manager_initialization_options
type ManagerOpts struct {
ShowPowerAlert bool
RestoreIdentifier string
}
// DfltManagerOpts is the set of options that gets used when nil is
// passed to `NewCentralManager()`.
var DfltManagerOpts = ManagerOpts{
ShowPowerAlert: false,
RestoreIdentifier: "",
}

View File

@ -1,54 +0,0 @@
package cbgo
import "unsafe"
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
// MutableCharacteristic: https://developer.apple.com/documentation/corebluetooth/cbmutablecharacteristic
type MutableCharacteristic struct {
ptr unsafe.Pointer
}
func NewMutableCharacteristic(uuid UUID, properties CharacteristicProperties,
value []byte, permissions AttributePermissions) MutableCharacteristic {
cuuid := C.CString(uuid.String())
defer C.free(unsafe.Pointer(cuuid))
cvalue := byteSliceToByteArr(value)
defer C.free(unsafe.Pointer(cvalue.data))
return MutableCharacteristic{
ptr: unsafe.Pointer(C.cb_mchr_alloc(cuuid, C.int(properties), &cvalue, C.int(permissions))),
}
}
// Characteristic converts a MutableCharacteristic into its underlying
// Characteristic.
func (c MutableCharacteristic) Characteristic() Characteristic {
return Characteristic{c.ptr}
}
// SetDescriptors: https://developer.apple.com/documentation/corebluetooth/cbmutablecharacteristic/1518827-descriptors
func (c MutableCharacteristic) SetDescriptors(mdscs []MutableDescriptor) {
dscs := mallocObjArr(len(mdscs))
defer C.free(unsafe.Pointer(dscs.objs))
for i, mdsc := range mdscs {
setObjArrElem(&dscs, i, mdsc.ptr)
}
C.cb_mchr_set_descriptors(c.ptr, &dscs)
}
// SetValue: https://developer.apple.com/documentation/corebluetooth/cbmutablecharacteristic/1519121-value
func (c MutableCharacteristic) SetValue(val []byte) {
ba := byteSliceToByteArr(val)
defer C.free(unsafe.Pointer(ba.data))
C.cb_mchr_set_value(c.ptr, &ba)
}

View File

@ -1,31 +0,0 @@
package cbgo
import "unsafe"
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
// MutableDescriptor: https://developer.apple.com/documentation/corebluetooth/cbmutabledescriptor
type MutableDescriptor struct {
ptr unsafe.Pointer
}
func NewMutableDescriptor(uuid UUID, value []byte) MutableDescriptor {
cuuid := C.CString(uuid.String())
defer C.free(unsafe.Pointer(cuuid))
cvalue := byteSliceToByteArr(value)
defer C.free(unsafe.Pointer(cvalue.data))
return MutableDescriptor{
ptr: unsafe.Pointer(C.cb_mdsc_alloc(cuuid, &cvalue)),
}
}
// Descriptor converts a MutableDescriptor into its underlying Descriptor.
func (d MutableDescriptor) Descriptor() Descriptor {
return Descriptor{d.ptr}
}

View File

@ -1,52 +0,0 @@
package cbgo
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
import "unsafe"
// MutableService: https://developer.apple.com/documentation/corebluetooth/cbmutableservice
type MutableService struct {
ptr unsafe.Pointer
}
func NewMutableService(uuid UUID, primary bool) MutableService {
cuuid := C.CString(uuid.String())
defer C.free(unsafe.Pointer(cuuid))
return MutableService{
ptr: unsafe.Pointer(C.cb_msvc_alloc(cuuid, C.bool(primary))),
}
}
// Service converts a MutableService into its underlying Service.
func (s MutableService) Service() Service {
return Service{s.ptr}
}
// SetCharacteristics: https://developer.apple.com/documentation/corebluetooth/cbmutableservice/1434317-characteristics
func (s MutableService) SetCharacteristics(mchrs []MutableCharacteristic) {
chrs := mallocObjArr(len(mchrs))
defer C.free(unsafe.Pointer(chrs.objs))
for i, mchr := range mchrs {
setObjArrElem(&chrs, i, mchr.ptr)
}
C.cb_msvc_set_characteristics(s.ptr, &chrs)
}
// SetIncludedServices: https://developer.apple.com/documentation/corebluetooth/cbmutableservice/1434320-includedservices
func (s MutableService) SetIncludedServices(msvcs []MutableService) {
svcs := mallocObjArr(len(msvcs))
defer C.free(unsafe.Pointer(svcs.objs))
for i, msvc := range msvcs {
setObjArrElem(&svcs, i, msvc.ptr)
}
C.cb_msvc_set_included_services(s.ptr, &svcs)
}

View File

@ -1,154 +0,0 @@
package cbgo
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
import (
"unsafe"
)
// PeripheralState: https://developer.apple.com/documentation/corebluetooth/cbperipheralstate
type PeripheralState int
const (
PeripheralStateDisconnected = PeripheralState(C.CBPeripheralStateDisconnected)
PeripheralStateConnecting = PeripheralState(C.CBPeripheralStateConnecting)
PeripheralStateConnected = PeripheralState(C.CBPeripheralStateConnected)
PeripheralStateDisconnecting = PeripheralState(C.CBPeripheralStateDisconnecting)
)
var prphPtrMap = newPtrMap()
// Peripheral: https://developer.apple.com/documentation/corebluetooth/cbperipheral
type Peripheral struct {
ptr unsafe.Pointer
}
func findPeripheralDlg(ptr unsafe.Pointer) PeripheralDelegate {
itf := prphPtrMap.find(ptr)
if itf == nil {
return nil
}
return itf.(PeripheralDelegate)
}
func addPeripheralDlg(ptr unsafe.Pointer, dlg PeripheralDelegate) {
prphPtrMap.add(ptr, dlg)
}
// Identifier: https://developer.apple.com/documentation/corebluetooth/cbpeer/1620687-identifier
func (p Peripheral) Identifier() UUID {
cstr := C.cb_peer_identifier(p.ptr)
return MustParseUUID(C.GoString(cstr))
}
// Name: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1519029-name
func (p Peripheral) Name() string {
cstr := C.cb_prph_name(p.ptr)
return C.GoString(cstr)
}
// SetDelegate: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518730-delegate
func (p Peripheral) SetDelegate(dlg PeripheralDelegate) {
addPeripheralDlg(p.ptr, dlg)
C.cb_prph_set_delegate(p.ptr, C.bool(dlg != nil))
}
// DiscoverServices: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518706-discoverservices
func (p Peripheral) DiscoverServices(svcUUIDs []UUID) {
arr := uuidsToStrArr(svcUUIDs)
defer freeStrArr(&arr)
C.cb_prph_discover_svcs(p.ptr, &arr)
}
// DiscoverIncludedServices: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1519014-discoverincludedservices
func (p Peripheral) DiscoverIncludedServices(svcUUIDs []UUID, svc Service) {
arr := uuidsToStrArr(svcUUIDs)
defer freeStrArr(&arr)
C.cb_prph_discover_included_svcs(p.ptr, &arr, svc.ptr)
}
// Services: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518978-services
func (p Peripheral) Services() []Service {
oa := C.cb_prph_services(p.ptr)
defer C.free(unsafe.Pointer(oa.objs))
svcs := make([]Service, oa.count)
for i, _ := range svcs {
obj := getObjArrElem(&oa, i)
svcs[i] = Service{ptr: obj}
}
return svcs
}
// DiscoverCharacteristics: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518797-discovercharacteristics
func (p Peripheral) DiscoverCharacteristics(chrUUIDs []UUID, svc Service) {
arr := uuidsToStrArr(chrUUIDs)
defer freeStrArr(&arr)
C.cb_prph_discover_chrs(p.ptr, svc.ptr, &arr)
}
// DiscoverDescriptors: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1519070-discoverdescriptorsforcharacteri
func (p Peripheral) DiscoverDescriptors(chr Characteristic) {
C.cb_prph_discover_dscs(p.ptr, chr.ptr)
}
// ReadCharacteristic: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518759-readvalueforcharacteristic
func (p Peripheral) ReadCharacteristic(chr Characteristic) {
C.cb_prph_read_chr(p.ptr, chr.ptr)
}
// ReadDescriptor: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518789-readvaluefordescriptor
func (p Peripheral) ReadDescriptor(dsc Descriptor) {
C.cb_prph_read_dsc(p.ptr, dsc.ptr)
}
// WriteCharacteristic: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518747-writevalue
func (p Peripheral) WriteCharacteristic(data []byte, chr Characteristic, withRsp bool) {
ba := byteSliceToByteArr(data)
defer C.free(unsafe.Pointer(ba.data))
C.cb_prph_write_chr(p.ptr, chr.ptr, &ba, chrWriteType(withRsp))
}
// WriteDescriptor: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1519107-writevalue
func (p Peripheral) WriteDescriptor(data []byte, dsc Descriptor) {
ba := byteSliceToByteArr(data)
defer C.free(unsafe.Pointer(ba.data))
C.cb_prph_write_dsc(p.ptr, dsc.ptr, &ba)
}
// MaximumWriteValueLength: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1620312-maximumwritevaluelengthfortype
func (p Peripheral) MaximumWriteValueLength(withRsp bool) int {
val := C.cb_prph_max_write_len(p.ptr, chrWriteType(withRsp))
return int(val)
}
// SetNotify: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518949-setnotifyvalue
func (p Peripheral) SetNotify(enabled bool, chr Characteristic) {
C.cb_prph_set_notify(p.ptr, C.bool(enabled), chr.ptr)
}
// PeripheralState: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1519113-state
func (p Peripheral) State() PeripheralState {
return PeripheralState(C.cb_prph_state(p.ptr))
}
// CanSendWriteWithoutResponse: https://developer.apple.com/documentation/corebluetooth/cbperipheral/2891512-cansendwritewithoutresponse
func (p Peripheral) CanSendWriteWithoutResponse() bool {
return bool(C.cb_prph_can_send_write_without_rsp(p.ptr))
}
// ReadRSSI: https://developer.apple.com/documentation/corebluetooth/cbperipheral/1519111-readrssi
func (p Peripheral) ReadRSSI() {
C.cb_prph_read_rssi(p.ptr)
}

View File

@ -1,76 +0,0 @@
package cbgo
// PeripheralDelegate: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate
type PeripheralDelegate interface {
// DidDiscoverServices: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518744-peripheral
DidDiscoverServices(prph Peripheral, err error)
// DidDiscoverIncludedServices: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1519124-peripheral
DidDiscoverIncludedServices(prph Peripheral, svc Service, err error)
// DidDiscoverCharacteristics: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518821-peripheral
DidDiscoverCharacteristics(prph Peripheral, svc Service, err error)
// DidDiscoverDescriptors: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518785-peripheral
DidDiscoverDescriptors(prph Peripheral, chr Characteristic, err error)
// DidUpdateValueForCharacteristic: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518708-peripheral
DidUpdateValueForCharacteristic(prph Peripheral, chr Characteristic, err error)
// DidUpdateValueForDescriptor: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518929-peripheral
DidUpdateValueForDescriptor(prph Peripheral, dsc Descriptor, err error)
// DidWriteValueForCharacteristic: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518823-peripheral
DidWriteValueForCharacteristic(prph Peripheral, chr Characteristic, err error)
// DidWriteValueForDescriptor: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1519062-peripheral
DidWriteValueForDescriptor(prph Peripheral, dsc Descriptor, err error)
// IsReadyToSendWriteWithoutResponse: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/2874034-peripheralisreadytosendwritewith
IsReadyToSendWriteWithoutResponse(prph Peripheral)
// DidUpdateNotificationState: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518768-peripheral
DidUpdateNotificationState(prph Peripheral, chr Characteristic, err error)
// DidReadRSSI: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1620304-peripheral
DidReadRSSI(prph Peripheral, rssi int, err error)
// DidUpdateName: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518801-peripheraldidupdatename
DidUpdateName(prph Peripheral)
// DidModifyServices: https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518865-peripheral
DidModifyServices(prph Peripheral, invSvcs []Service)
}
// PeripheralDelegateBase implements the PeripheralDelegate interface with stub
// functions. Embed this in your delegate type if you only want to define a
// subset of the PeripheralDelegate interface.
type PeripheralDelegateBase struct {
}
func (b *PeripheralDelegateBase) DidDiscoverServices(prph Peripheral, err error) {
}
func (b *PeripheralDelegateBase) DidDiscoverIncludedServices(prph Peripheral, svc Service, err error) {
}
func (b *PeripheralDelegateBase) DidDiscoverCharacteristics(prph Peripheral, svc Service, err error) {
}
func (b *PeripheralDelegateBase) DidDiscoverDescriptors(prph Peripheral, chr Characteristic, err error) {
}
func (b *PeripheralDelegateBase) DidUpdateValueForCharacteristic(prph Peripheral, chr Characteristic, err error) {
}
func (b *PeripheralDelegateBase) DidUpdateValueForDescriptor(prph Peripheral, dsc Descriptor, err error) {
}
func (b *PeripheralDelegateBase) DidWriteValueForCharacteristic(prph Peripheral, chr Characteristic, err error) {
}
func (b *PeripheralDelegateBase) DidWriteValueForDescriptor(prph Peripheral, dsc Descriptor, err error) {
}
func (b *PeripheralDelegateBase) IsReadyToSendWriteWithoutResponse(prph Peripheral) {
}
func (b *PeripheralDelegateBase) DidUpdateNotificationState(prph Peripheral, chr Characteristic, err error) {
}
func (b *PeripheralDelegateBase) DidReadRSSI(prph Peripheral, rssi int, err error) {
}
func (b *PeripheralDelegateBase) DidUpdateName(prph Peripheral) {
}
func (b *PeripheralDelegateBase) DidModifyServices(prph Peripheral, invSvcs []Service) {
}

View File

@ -1,146 +0,0 @@
package cbgo
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
import (
"unsafe"
)
// PeripheralManagerConnectionLatency: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerconnectionlatency
type PeripheralManagerConnectionLatency int
const (
PeripheralManagerConnectionLatencyLow = PeripheralManagerConnectionLatency(C.CBPeripheralManagerConnectionLatencyLow)
PeripheralManagerConnectionLatencyMedium = PeripheralManagerConnectionLatency(C.CBPeripheralManagerConnectionLatencyMedium)
PeripheralManagerConnectionLatencyHigh = PeripheralManagerConnectionLatency(C.CBPeripheralManagerConnectionLatencyHigh)
)
// PeripheralManagerRestoreOpts: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/peripheral_manager_state_restoration_options
type PeripheralManagerRestoreOpts struct {
Services []MutableService
AdvertisementData *AdvData
}
// PeripheralManager: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager
type PeripheralManager struct {
ptr unsafe.Pointer
}
var pmgrPtrMap = newPtrMap()
func findPeripheralManagerDlg(ptr unsafe.Pointer) PeripheralManagerDelegate {
itf := pmgrPtrMap.find(ptr)
if itf == nil {
return nil
}
return itf.(PeripheralManagerDelegate)
}
// NewPeripheralManager creates a peripheral manager. Specify a nil `opts`
// value for defaults. Don't forget to call `SetDelegate()` afterwards!
func NewPeripheralManager(opts *ManagerOpts) PeripheralManager {
if opts == nil {
opts = &DfltManagerOpts
}
pwrAlert := C.bool(opts.ShowPowerAlert)
restoreID := (*C.char)(nil)
if opts.RestoreIdentifier != "" {
restoreID = C.CString(opts.RestoreIdentifier)
defer C.free(unsafe.Pointer(restoreID))
}
return PeripheralManager{
ptr: unsafe.Pointer(C.cb_alloc_pmgr(pwrAlert, restoreID)),
}
}
// SetDelegate configures a receiver for a central manager's asynchronous
// callbacks.
func (pm PeripheralManager) SetDelegate(d PeripheralManagerDelegate) {
if d != nil {
pmgrPtrMap.add(pm.ptr, d)
}
C.cb_pmgr_set_delegate(pm.ptr, C.bool(d != nil))
}
// State: https://developer.apple.com/documentation/corebluetooth/cbmanager/1648600-state
func (pm PeripheralManager) State() ManagerState {
return ManagerState(C.cb_pmgr_state(pm.ptr))
}
// AddService: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393255-addservice
func (pm PeripheralManager) AddService(svc MutableService) {
C.cb_pmgr_add_svc(pm.ptr, svc.ptr)
}
// RemoveService: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393287-removeservice
func (pm PeripheralManager) RemoveService(svc MutableService) {
C.cb_pmgr_remove_svc(pm.ptr, svc.ptr)
}
// RemoveAllServices: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393269-removeallservices
func (pm PeripheralManager) RemoveAllServices() {
C.cb_pmgr_remove_all_svcs(pm.ptr)
}
// StartAdvertising: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393252-startadvertising
func (pm PeripheralManager) StartAdvertising(ad AdvData) {
cad := C.struct_adv_data{}
if len(ad.IBeaconData) > 0 {
cad.ibeacon_data = byteSliceToByteArr(ad.IBeaconData)
defer C.free(unsafe.Pointer(cad.ibeacon_data.data))
} else {
if len(ad.LocalName) > 0 {
cad.name = C.CString(ad.LocalName)
defer C.free(unsafe.Pointer(cad.name))
}
cad.svc_uuids = uuidsToStrArr(ad.ServiceUUIDs)
defer freeStrArr(&cad.svc_uuids)
}
C.cb_pmgr_start_adv(pm.ptr, &cad)
}
// StopAdvertising: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393275-stopadvertising
func (pm PeripheralManager) StopAdvertising() {
C.cb_pmgr_stop_adv(pm.ptr)
}
// IsAdvertising: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393291-isadvertising
func (pm PeripheralManager) IsAdvertising() bool {
return bool(C.cb_pmgr_is_adv(pm.ptr))
}
// UpdateValue: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393281-updatevalue
func (pm PeripheralManager) UpdateValue(value []byte, chr Characteristic, centrals []Central) bool {
ba := byteSliceToByteArr(value)
defer C.free(unsafe.Pointer(ba.data))
oa := mallocObjArr(len(centrals))
defer C.free(unsafe.Pointer(oa.objs))
for i, c := range centrals {
setObjArrElem(&oa, i, c.ptr)
}
return bool(C.cb_pmgr_update_val(pm.ptr, &ba, chr.ptr, &oa))
}
// RespondToRequest: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393293-respondtorequest
func (pm PeripheralManager) RespondToRequest(req ATTRequest, result ATTError) {
C.cb_pmgr_respond_to_req(pm.ptr, req.ptr, C.int(result))
}
// SetDesiredConnectionLatency: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393277-setdesiredconnectionlatency
func (pm PeripheralManager) SetDesiredConnectionLatency(latency PeripheralManagerConnectionLatency, central Central) {
C.cb_pmgr_set_conn_latency(pm.ptr, C.int(latency), central.ptr)
}

View File

@ -1,56 +0,0 @@
package cbgo
// https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate
type PeripheralManagerDelegate interface {
// PeripheralManagerDidUpdateState: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/1393271-peripheralmanagerdidupdatestate
PeripheralManagerDidUpdateState(pmgr PeripheralManager)
// PeripheralManagerWillRestoreState: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/1393317-peripheralmanager
PeripheralManagerWillRestoreState(pmgr PeripheralManager, opts PeripheralManagerRestoreOpts)
// DidAddService: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/1393279-peripheralmanager
DidAddService(pmgr PeripheralManager, svc Service, err error)
// DidStartAdvertising: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/1393321-peripheralmanagerdidstartadverti
DidStartAdvertising(pmgr PeripheralManager, err error)
// CentralDidSubscribe: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/1393261-peripheralmanager
CentralDidSubscribe(pmgr PeripheralManager, cent Central, chr Characteristic)
// CentralDidUnsubscribe: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/1393289-peripheralmanager
CentralDidUnsubscribe(pmgr PeripheralManager, cent Central, chr Characteristic)
// IsReadyToUpdateSubscribers: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/1393248-peripheralmanagerisreadytoupdate
IsReadyToUpdateSubscribers(pmgr PeripheralManager)
// DidReceiveReadRequest: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/1393257-peripheralmanager
DidReceiveReadRequest(pmgr PeripheralManager, req ATTRequest)
// DidReceiveWriteRequests: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/1393315-peripheralmanager
DidReceiveWriteRequests(pmgr PeripheralManager, reqs []ATTRequest)
}
// PeripheralManagerDelegateBase implements the PeripheralManagerDelegate
// interface with stub functions. Embed this in your delegate type if you only
// want to define a subset of the PeripheralManagerDelegate interface.
type PeripheralManagerDelegateBase struct {
}
func (b *PeripheralManagerDelegateBase) PeripheralManagerDidUpdateState(pmgr PeripheralManager) {
}
func (b *PeripheralManagerDelegateBase) PeripheralManagerWillRestoreState(pmgr PeripheralManager, opts PeripheralManagerRestoreOpts) {
}
func (b *PeripheralManagerDelegateBase) DidAddService(pmgr PeripheralManager, svc Service, err error) {
}
func (b *PeripheralManagerDelegateBase) DidStartAdvertising(pmgr PeripheralManager, err error) {
}
func (b *PeripheralManagerDelegateBase) CentralDidSubscribe(pmgr PeripheralManager, cent Central, chr Characteristic) {
}
func (b *PeripheralManagerDelegateBase) CentralDidUnsubscribe(pmgr PeripheralManager, cent Central, chr Characteristic) {
}
func (b *PeripheralManagerDelegateBase) IsReadyToUpdateSubscribers(pmgr PeripheralManager) {
}
func (b *PeripheralManagerDelegateBase) DidReceiveReadRequest(pmgr PeripheralManager, req ATTRequest) {
}
func (b *PeripheralManagerDelegateBase) DidReceiveWriteRequests(pmgr PeripheralManager, reqs []ATTRequest) {
}

View File

@ -1,252 +0,0 @@
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
#import <CoreLocation/CoreLocation.h>
#import "bt.h"
// pmgr.m: C functions for interfacing with CoreBluetooth peripheral
// functionality. This is necessary because Go code cannot execute some
// objective C constructs directly.
CBPeripheralManager *
cb_alloc_pmgr(bool pwr_alert, const char *restore_id)
{
// Ensure queue is initialized.
bt_init();
NSMutableDictionary *opts = [[NSMutableDictionary alloc] init];
if (pwr_alert) {
[opts setObject:[NSNumber numberWithBool:pwr_alert]
forKey:CBPeripheralManagerOptionShowPowerAlertKey];
}
if (restore_id != NULL) {
[opts setObject:str_to_nsstring(restore_id)
forKey:CBPeripheralManagerOptionRestoreIdentifierKey];
}
CBPeripheralManager *pm = [[CBPeripheralManager alloc] initWithDelegate:bt_dlg
queue:bt_queue
options:opts];
[pm retain];
return pm;
}
void
cb_pmgr_set_delegate(void *pmgr, bool set)
{
BTDlg *del;
if (set) {
del = bt_dlg;
} else {
del = nil;
}
((CBPeripheralManager *)pmgr).delegate = del;
}
int
cb_pmgr_state(void *pmgr)
{
CBPeripheralManager *pm = pmgr;
return [pm state];
}
void
cb_pmgr_add_svc(void *pmgr, void *svc)
{
[(CBPeripheralManager *)pmgr addService:svc];
}
void
cb_pmgr_remove_svc(void *pmgr, void *svc)
{
[(CBPeripheralManager *)pmgr removeService:svc];
}
void
cb_pmgr_remove_all_svcs(void *pmgr)
{
[(CBPeripheralManager *)pmgr removeAllServices];
}
void
cb_pmgr_start_adv(void *pmgr, const struct adv_data *ad)
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict autorelease];
// iBeacon data is mutually exclusing with the rest of the fields.
if (ad->ibeacon_data.length > 0) {
NSData *nsd = byte_arr_to_nsdata(&ad->ibeacon_data);
[nsd autorelease];
[dict setObject:nsd forKey:@"kCBAdvDataAppleBeaconKey"];
} else {
if (ad->name != NULL) {
NSString *nss = str_to_nsstring(ad->name);
[nss autorelease];
[dict setObject:nss
forKey:CBAdvertisementDataLocalNameKey];
}
if (ad->svc_uuids.count > 0) {
NSArray *arr_svc_uuids = strs_to_cbuuids(&ad->svc_uuids);
[arr_svc_uuids autorelease];
[dict setObject:arr_svc_uuids
forKey:CBAdvertisementDataServiceUUIDsKey];
}
}
[(CBPeripheralManager *)pmgr startAdvertising:dict];
}
void
cb_pmgr_stop_adv(void *pmgr)
{
[(CBPeripheralManager *)pmgr stopAdvertising];
}
bool
cb_pmgr_is_adv(void *pmgr)
{
return [(CBPeripheralManager *)pmgr isAdvertising];
}
bool
cb_pmgr_update_val(void *pmgr, const struct byte_arr *value, void *chr, const struct obj_arr *centrals)
{
NSData *nsd = byte_arr_to_nsdata(value);
[nsd autorelease];
NSArray *nsa = obj_arr_to_nsarray(centrals);
[nsa autorelease];
return [(CBPeripheralManager *)pmgr updateValue:nsd
forCharacteristic:chr
onSubscribedCentrals:nsa];
}
void
cb_pmgr_respond_to_req(void *pmgr, void *req, int result)
{
[(CBPeripheralManager *)pmgr respondToRequest:req withResult:result];
}
void
cb_pmgr_set_conn_latency(void *pmgr, int latency, void *central)
{
[(CBPeripheralManager *)pmgr setDesiredConnectionLatency:latency forCentral:central];
}
int
cb_cent_maximum_update_len(void *cent)
{
return ((CBCentral *)cent).maximumUpdateValueLength;
}
CBMutableService *
cb_msvc_alloc(const char *uuid, bool primary)
{
CBUUID *cbuuid = str_to_cbuuid(uuid);
CBMutableService *svc = [[CBMutableService alloc] initWithType:cbuuid primary:primary];
[svc retain];
return svc;
}
void
cb_msvc_set_characteristics(void *msvc, const struct obj_arr *mchrs)
{
NSArray *nsa = obj_arr_to_nsarray(mchrs);
[nsa autorelease];
((CBMutableService *)msvc).characteristics = nsa;
}
void
cb_msvc_set_included_services(void *msvc, const struct obj_arr *msvcs)
{
NSArray *nsa = obj_arr_to_nsarray(msvcs);
[nsa autorelease];
((CBMutableService *)msvc).includedServices = nsa;
}
CBMutableCharacteristic *
cb_mchr_alloc(const char *uuid, int properties, const struct byte_arr *value, int permissions)
{
CBUUID *cbuuid = str_to_cbuuid(uuid);
NSData *nsd = byte_arr_to_nsdata(value);
CBMutableCharacteristic *chr = [[CBMutableCharacteristic alloc] initWithType:cbuuid
properties:properties
value:nsd
permissions:permissions];
[chr retain];
return chr;
}
void
cb_mchr_set_descriptors(void *mchr, const struct obj_arr *mdscs)
{
NSArray *nsa = obj_arr_to_nsarray(mdscs);
[nsa autorelease];
((CBMutableCharacteristic *)mchr).descriptors = nsa;
}
void
cb_mchr_set_value(void *mchr, const struct byte_arr *val)
{
((CBMutableCharacteristic *)mchr).value = byte_arr_to_nsdata(val);
}
CBMutableDescriptor *
cb_mdsc_alloc(const char *uuid, const struct byte_arr *value)
{
CBUUID *cbuuid = str_to_cbuuid(uuid);
NSData *nsd = byte_arr_to_nsdata(value);
CBMutableDescriptor *dsc = [[CBMutableDescriptor alloc] initWithType:cbuuid
value:nsd];
[dsc retain];
return dsc;
}
CBCentral *
cb_atr_central(void *atr)
{
return ((CBATTRequest *)atr).central;
}
CBCharacteristic *
cb_atr_characteristic(void *atr)
{
return ((CBATTRequest *)atr).characteristic;
}
struct byte_arr
cb_atr_value(void *atr)
{
NSData *nsd = ((CBATTRequest *)atr).value;
return nsdata_to_byte_arr(nsd);
}
void
cb_atr_set_value(void *atr, const struct byte_arr *ba)
{
NSData *nsd = byte_arr_to_nsdata(ba);
((CBATTRequest *)atr).value = nsd;
}
int
cb_atr_offset(void *atr)
{
return ((CBATTRequest *)atr).offset;
}

View File

@ -1,41 +0,0 @@
package cbgo
import (
"sync"
"unsafe"
)
// ptrMap is a thread-safe map with pointer keys and generic values.
type ptrMap struct {
m map[unsafe.Pointer]interface{}
mtx sync.RWMutex
}
func newPtrMap() *ptrMap {
return &ptrMap{
m: map[unsafe.Pointer]interface{}{},
}
}
func (pm *ptrMap) find(p unsafe.Pointer) interface{} {
pm.mtx.RLock()
defer pm.mtx.RUnlock()
return pm.m[p]
}
func (pm *ptrMap) add(p unsafe.Pointer, itf interface{}) error {
pm.mtx.Lock()
defer pm.mtx.Unlock()
pm.m[p] = itf
return nil
}
func (pm *ptrMap) del(p unsafe.Pointer) {
pm.mtx.Lock()
defer pm.mtx.Unlock()
delete(pm.m, p)
}

View File

@ -1,59 +0,0 @@
package cbgo
import "unsafe"
/*
// See cutil.go for C compiler flags.
#import "bt.h"
*/
import "C"
// Service: https://developer.apple.com/documentation/corebluetooth/cbservice
type Service struct {
ptr unsafe.Pointer
}
// UUID: https://developer.apple.com/documentation/corebluetooth/cbattribute/1620638-uuid
func (s Service) UUID() UUID {
cstr := C.cb_svc_uuid(s.ptr)
return MustParseUUID(C.GoString(cstr))
}
// Peripheral: https://developer.apple.com/documentation/corebluetooth/cbservice/1434334-peripheral
func (s Service) Peripheral() Peripheral {
prphPtr := C.cb_svc_peripheral(s.ptr)
return Peripheral{prphPtr}
}
// IsPrimary: https://developer.apple.com/documentation/corebluetooth/cbservice/1434326-isprimary
func (s Service) IsPrimary() bool {
return bool(C.cb_svc_is_primary(s.ptr))
}
// Characteristics: https://developer.apple.com/documentation/corebluetooth/cbservice/1434319-characteristics
func (s Service) Characteristics() []Characteristic {
oa := C.cb_svc_characteristics(s.ptr)
defer C.free(unsafe.Pointer(oa.objs))
chrs := make([]Characteristic, oa.count)
for i, _ := range chrs {
obj := getObjArrElem(&oa, i)
chrs[i] = Characteristic{ptr: obj}
}
return chrs
}
// IncludedServices: https://developer.apple.com/documentation/corebluetooth/cbservice/1434324-includedservices
func (s Service) IncludedServices() []Service {
oa := C.cb_svc_included_svcs(s.ptr)
defer C.free(unsafe.Pointer(oa.objs))
svcs := make([]Service, oa.count)
for i, _ := range svcs {
obj := getObjArrElem(&oa, i)
svcs[i] = Service{ptr: obj}
}
return svcs
}

View File

@ -1,200 +0,0 @@
#import "bt.h"
struct byte_arr
nsdata_to_byte_arr(const NSData *nsdata)
{
return (struct byte_arr) {
.data = [nsdata bytes],
.length = [nsdata length],
};
}
NSData *
byte_arr_to_nsdata(const struct byte_arr *ba)
{
if (ba->length == 0) {
return nil;
} else {
return [NSData dataWithBytes: ba->data length: ba->length];
}
}
struct obj_arr
nsarray_to_obj_arr(const NSArray *arr)
{
struct obj_arr oa = {0};
if (arr != nil && [arr count] > 0) {
oa.count = [arr count],
oa.objs = malloc(oa.count * sizeof (void *)),
assert(oa.objs != NULL);
for (int i = 0; i < oa.count; i++) {
oa.objs[i] = [arr objectAtIndex:i];
}
}
return oa;
}
NSArray *
obj_arr_to_nsarray(const struct obj_arr *oa)
{
NSMutableArray *nsa = [[NSMutableArray alloc] init];
[nsa autorelease];
for (int i = 0; i < oa->count; i++) {
[nsa addObject:oa->objs[i]];
}
return nsa;
}
NSString *
str_to_nsstring(const char *s)
{
return [[NSString alloc] initWithCString:s encoding:NSUTF8StringEncoding];
}
struct bt_error
nserror_to_bt_error(const NSError *err)
{
if (err == NULL) {
return (struct bt_error) {0};
} else {
return (struct bt_error) {
.msg = [err.localizedDescription UTF8String],
.code = err.code,
};
}
}
NSUUID *
str_to_nsuuid(const char *s)
{
NSString *nss = str_to_nsstring(s);
return [[NSUUID alloc] initWithUUIDString:nss];
}
CBUUID *
str_to_cbuuid(const char *s)
{
NSString *nss = str_to_nsstring(s);
return [CBUUID UUIDWithString:nss];
}
NSArray *
strs_to_nsuuids(const struct string_arr *sa)
{
if (sa == nil || sa->count == 0) {
return nil;
};
NSMutableArray *arr = [[NSMutableArray alloc] init];
[arr autorelease];
for (int i = 0; i < sa->count; i++) {
[arr addObject:str_to_nsuuid(sa->strings[i])];
}
return arr;
}
NSArray *
strs_to_cbuuids(const struct string_arr *sa)
{
if (sa == nil || sa->count == 0) {
return nil;
};
NSMutableArray *arr = [[NSMutableArray alloc] init];
[arr autorelease];
for (int i = 0; i < sa->count; i++) {
[arr addObject:str_to_cbuuid(sa->strings[i])];
}
return arr;
}
NSArray *
strs_to_nsstrings(const struct string_arr *sa)
{
if (sa == nil || sa->count == 0) {
return nil;
};
NSMutableArray *arr = [[NSMutableArray alloc] init];
[arr autorelease];
for (int i = 0; i < sa->count; i++) {
[arr addObject:str_to_nsstring(sa->strings[i])];
}
return arr;
}
struct string_arr
cbuuids_to_strs(const NSArray *cbuuids)
{
struct string_arr sa = {0};
if (cbuuids != nil && [cbuuids count] > 0) {
sa.count = [cbuuids count];
sa.strings = malloc(sa.count * sizeof (char *));
assert(sa.strings != NULL);
for (int i = 0; i < sa.count; i++) {
sa.strings[i] = [[[cbuuids objectAtIndex:i] UUIDString] UTF8String];
}
}
return sa;
}
int
dict_int(NSDictionary *dict, NSString *key, int dflt)
{
NSNumber *nsn = [dict objectForKey:key];
if (nsn == nil) {
return dflt;
} else {
return [nsn intValue];
}
}
const char *
dict_string(NSDictionary *dict, NSString *key)
{
return [[dict objectForKey:key] UTF8String];
}
const void *
dict_data(NSDictionary *dict, NSString *key, int *out_len)
{
NSData *data;
data = [dict objectForKey:key];
*out_len = [data length];
return [data bytes];
}
const struct byte_arr
dict_bytes(NSDictionary *dict, NSString *key)
{
const NSData *nsdata = [dict objectForKey:key];
return nsdata_to_byte_arr(nsdata);
}
void
dict_set_bool(NSMutableDictionary *dict, NSString *key, bool val)
{
[dict setObject:[NSNumber numberWithBool:val] forKey:key];
}
void
dict_set_int(NSMutableDictionary *dict, NSString *key, int val)
{
[dict setObject:[NSNumber numberWithInt:val] forKey:key];
}

View File

@ -1,23 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test

View File

@ -1,13 +0,0 @@
language: go
go:
- 1.7.x
- 1.8.x
- 1.9.x
- tip
sudo: false
before_install:
- go get github.com/axw/gocov/gocov
- go get github.com/mattn/goveralls
- if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
script:
- $HOME/gopath/bin/goveralls -service=travis-ci

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014 Fatih Arslan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,163 +0,0 @@
# Structs [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/structs) [![Build Status](http://img.shields.io/travis/fatih/structs.svg?style=flat-square)](https://travis-ci.org/fatih/structs) [![Coverage Status](http://img.shields.io/coveralls/fatih/structs.svg?style=flat-square)](https://coveralls.io/r/fatih/structs)
Structs contains various utilities to work with Go (Golang) structs. It was
initially used by me to convert a struct into a `map[string]interface{}`. With
time I've added other utilities for structs. It's basically a high level
package based on primitives from the reflect package. Feel free to add new
functions or improve the existing code.
## Install
```bash
go get github.com/fatih/structs
```
## Usage and Examples
Just like the standard lib `strings`, `bytes` and co packages, `structs` has
many global functions to manipulate or organize your struct data. Lets define
and declare a struct:
```go
type Server struct {
Name string `json:"name,omitempty"`
ID int
Enabled bool
users []string // not exported
http.Server // embedded
}
server := &Server{
Name: "gopher",
ID: 123456,
Enabled: true,
}
```
```go
// Convert a struct to a map[string]interface{}
// => {"Name":"gopher", "ID":123456, "Enabled":true}
m := structs.Map(server)
// Convert the values of a struct to a []interface{}
// => ["gopher", 123456, true]
v := structs.Values(server)
// Convert the names of a struct to a []string
// (see "Names methods" for more info about fields)
n := structs.Names(server)
// Convert the values of a struct to a []*Field
// (see "Field methods" for more info about fields)
f := structs.Fields(server)
// Return the struct name => "Server"
n := structs.Name(server)
// Check if any field of a struct is initialized or not.
h := structs.HasZero(server)
// Check if all fields of a struct is initialized or not.
z := structs.IsZero(server)
// Check if server is a struct or a pointer to struct
i := structs.IsStruct(server)
```
### Struct methods
The structs functions can be also used as independent methods by creating a new
`*structs.Struct`. This is handy if you want to have more control over the
structs (such as retrieving a single Field).
```go
// Create a new struct type:
s := structs.New(server)
m := s.Map() // Get a map[string]interface{}
v := s.Values() // Get a []interface{}
f := s.Fields() // Get a []*Field
n := s.Names() // Get a []string
f := s.Field(name) // Get a *Field based on the given field name
f, ok := s.FieldOk(name) // Get a *Field based on the given field name
n := s.Name() // Get the struct name
h := s.HasZero() // Check if any field is uninitialized
z := s.IsZero() // Check if all fields are uninitialized
```
### Field methods
We can easily examine a single Field for more detail. Below you can see how we
get and interact with various field methods:
```go
s := structs.New(server)
// Get the Field struct for the "Name" field
name := s.Field("Name")
// Get the underlying value, value => "gopher"
value := name.Value().(string)
// Set the field's value
name.Set("another gopher")
// Get the field's kind, kind => "string"
name.Kind()
// Check if the field is exported or not
if name.IsExported() {
fmt.Println("Name field is exported")
}
// Check if the value is a zero value, such as "" for string, 0 for int
if !name.IsZero() {
fmt.Println("Name is initialized")
}
// Check if the field is an anonymous (embedded) field
if !name.IsEmbedded() {
fmt.Println("Name is not an embedded field")
}
// Get the Field's tag value for tag name "json", tag value => "name,omitempty"
tagValue := name.Tag("json")
```
Nested structs are supported too:
```go
addrField := s.Field("Server").Field("Addr")
// Get the value for addr
a := addrField.Value().(string)
// Or get all fields
httpServer := s.Field("Server").Fields()
```
We can also get a slice of Fields from the Struct type to iterate over all
fields. This is handy if you wish to examine all fields:
```go
s := structs.New(server)
for _, f := range s.Fields() {
fmt.Printf("field name: %+v\n", f.Name())
if f.IsExported() {
fmt.Printf("value : %+v\n", f.Value())
fmt.Printf("is zero : %+v\n", f.IsZero())
}
}
```
## Credits
* [Fatih Arslan](https://github.com/fatih)
* [Cihangir Savas](https://github.com/cihangir)
## License
The MIT License (MIT) - see LICENSE.md for more details

View File

@ -1,141 +0,0 @@
package structs
import (
"errors"
"fmt"
"reflect"
)
var (
errNotExported = errors.New("field is not exported")
errNotSettable = errors.New("field is not settable")
)
// Field represents a single struct field that encapsulates high level
// functions around the field.
type Field struct {
value reflect.Value
field reflect.StructField
defaultTag string
}
// Tag returns the value associated with key in the tag string. If there is no
// such key in the tag, Tag returns the empty string.
func (f *Field) Tag(key string) string {
return f.field.Tag.Get(key)
}
// Value returns the underlying value of the field. It panics if the field
// is not exported.
func (f *Field) Value() interface{} {
return f.value.Interface()
}
// IsEmbedded returns true if the given field is an anonymous field (embedded)
func (f *Field) IsEmbedded() bool {
return f.field.Anonymous
}
// IsExported returns true if the given field is exported.
func (f *Field) IsExported() bool {
return f.field.PkgPath == ""
}
// IsZero returns true if the given field is not initialized (has a zero value).
// It panics if the field is not exported.
func (f *Field) IsZero() bool {
zero := reflect.Zero(f.value.Type()).Interface()
current := f.Value()
return reflect.DeepEqual(current, zero)
}
// Name returns the name of the given field
func (f *Field) Name() string {
return f.field.Name
}
// Kind returns the fields kind, such as "string", "map", "bool", etc ..
func (f *Field) Kind() reflect.Kind {
return f.value.Kind()
}
// Set sets the field to given value v. It returns an error if the field is not
// settable (not addressable or not exported) or if the given value's type
// doesn't match the fields type.
func (f *Field) Set(val interface{}) error {
// we can't set unexported fields, so be sure this field is exported
if !f.IsExported() {
return errNotExported
}
// do we get here? not sure...
if !f.value.CanSet() {
return errNotSettable
}
given := reflect.ValueOf(val)
if f.value.Kind() != given.Kind() {
return fmt.Errorf("wrong kind. got: %s want: %s", given.Kind(), f.value.Kind())
}
f.value.Set(given)
return nil
}
// Zero sets the field to its zero value. It returns an error if the field is not
// settable (not addressable or not exported).
func (f *Field) Zero() error {
zero := reflect.Zero(f.value.Type()).Interface()
return f.Set(zero)
}
// Fields returns a slice of Fields. This is particular handy to get the fields
// of a nested struct . A struct tag with the content of "-" ignores the
// checking of that particular field. Example:
//
// // Field is ignored by this package.
// Field *http.Request `structs:"-"`
//
// It panics if field is not exported or if field's kind is not struct
func (f *Field) Fields() []*Field {
return getFields(f.value, f.defaultTag)
}
// Field returns the field from a nested struct. It panics if the nested struct
// is not exported or if the field was not found.
func (f *Field) Field(name string) *Field {
field, ok := f.FieldOk(name)
if !ok {
panic("field not found")
}
return field
}
// FieldOk returns the field from a nested struct. The boolean returns whether
// the field was found (true) or not (false).
func (f *Field) FieldOk(name string) (*Field, bool) {
value := &f.value
// value must be settable so we need to make sure it holds the address of the
// variable and not a copy, so we can pass the pointer to strctVal instead of a
// copy (which is not assigned to any variable, hence not settable).
// see "https://blog.golang.org/laws-of-reflection#TOC_8."
if f.value.Kind() != reflect.Ptr {
a := f.value.Addr()
value = &a
}
v := strctVal(value.Interface())
t := v.Type()
field, ok := t.FieldByName(name)
if !ok {
return nil, false
}
return &Field{
field: field,
value: v.FieldByName(name),
}, true
}

View File

@ -1,584 +0,0 @@
// Package structs contains various utilities functions to work with structs.
package structs
import (
"fmt"
"reflect"
)
var (
// DefaultTagName is the default tag name for struct fields which provides
// a more granular to tweak certain structs. Lookup the necessary functions
// for more info.
DefaultTagName = "structs" // struct's field default tag name
)
// Struct encapsulates a struct type to provide several high level functions
// around the struct.
type Struct struct {
raw interface{}
value reflect.Value
TagName string
}
// New returns a new *Struct with the struct s. It panics if the s's kind is
// not struct.
func New(s interface{}) *Struct {
return &Struct{
raw: s,
value: strctVal(s),
TagName: DefaultTagName,
}
}
// Map converts the given struct to a map[string]interface{}, where the keys
// of the map are the field names and the values of the map the associated
// values of the fields. The default key string is the struct field name but
// can be changed in the struct field's tag value. The "structs" key in the
// struct's field tag value is the key name. Example:
//
// // Field appears in map as key "myName".
// Name string `structs:"myName"`
//
// A tag value with the content of "-" ignores that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// A tag value with the content of "string" uses the stringer to get the value. Example:
//
// // The value will be output of Animal's String() func.
// // Map will panic if Animal does not implement String().
// Field *Animal `structs:"field,string"`
//
// A tag value with the option of "flatten" used in a struct field is to flatten its fields
// in the output map. Example:
//
// // The FieldStruct's fields will be flattened into the output map.
// FieldStruct time.Time `structs:",flatten"`
//
// A tag value with the option of "omitnested" stops iterating further if the type
// is a struct. Example:
//
// // Field is not processed further by this package.
// Field time.Time `structs:"myName,omitnested"`
// Field *http.Request `structs:",omitnested"`
//
// A tag value with the option of "omitempty" ignores that particular field if
// the field value is empty. Example:
//
// // Field appears in map as key "myName", but the field is
// // skipped if empty.
// Field string `structs:"myName,omitempty"`
//
// // Field appears in map as key "Field" (the default), but
// // the field is skipped if empty.
// Field string `structs:",omitempty"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected.
func (s *Struct) Map() map[string]interface{} {
out := make(map[string]interface{})
s.FillMap(out)
return out
}
// FillMap is the same as Map. Instead of returning the output, it fills the
// given map.
func (s *Struct) FillMap(out map[string]interface{}) {
if out == nil {
return
}
fields := s.structFields()
for _, field := range fields {
name := field.Name
val := s.value.FieldByName(name)
isSubStruct := false
var finalVal interface{}
tagName, tagOpts := parseTag(field.Tag.Get(s.TagName))
if tagName != "" {
name = tagName
}
// if the value is a zero value and the field is marked as omitempty do
// not include
if tagOpts.Has("omitempty") {
zero := reflect.Zero(val.Type()).Interface()
current := val.Interface()
if reflect.DeepEqual(current, zero) {
continue
}
}
if !tagOpts.Has("omitnested") {
finalVal = s.nested(val)
v := reflect.ValueOf(val.Interface())
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
switch v.Kind() {
case reflect.Map, reflect.Struct:
isSubStruct = true
}
} else {
finalVal = val.Interface()
}
if tagOpts.Has("string") {
s, ok := val.Interface().(fmt.Stringer)
if ok {
out[name] = s.String()
}
continue
}
if isSubStruct && (tagOpts.Has("flatten")) {
for k := range finalVal.(map[string]interface{}) {
out[k] = finalVal.(map[string]interface{})[k]
}
} else {
out[name] = finalVal
}
}
}
// Values converts the given s struct's field values to a []interface{}. A
// struct tag with the content of "-" ignores the that particular field.
// Example:
//
// // Field is ignored by this package.
// Field int `structs:"-"`
//
// A value with the option of "omitnested" stops iterating further if the type
// is a struct. Example:
//
// // Fields is not processed further by this package.
// Field time.Time `structs:",omitnested"`
// Field *http.Request `structs:",omitnested"`
//
// A tag value with the option of "omitempty" ignores that particular field and
// is not added to the values if the field value is empty. Example:
//
// // Field is skipped if empty
// Field string `structs:",omitempty"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected.
func (s *Struct) Values() []interface{} {
fields := s.structFields()
var t []interface{}
for _, field := range fields {
val := s.value.FieldByName(field.Name)
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
// if the value is a zero value and the field is marked as omitempty do
// not include
if tagOpts.Has("omitempty") {
zero := reflect.Zero(val.Type()).Interface()
current := val.Interface()
if reflect.DeepEqual(current, zero) {
continue
}
}
if tagOpts.Has("string") {
s, ok := val.Interface().(fmt.Stringer)
if ok {
t = append(t, s.String())
}
continue
}
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
// look out for embedded structs, and convert them to a
// []interface{} to be added to the final values slice
t = append(t, Values(val.Interface())...)
} else {
t = append(t, val.Interface())
}
}
return t
}
// Fields returns a slice of Fields. A struct tag with the content of "-"
// ignores the checking of that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// It panics if s's kind is not struct.
func (s *Struct) Fields() []*Field {
return getFields(s.value, s.TagName)
}
// Names returns a slice of field names. A struct tag with the content of "-"
// ignores the checking of that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// It panics if s's kind is not struct.
func (s *Struct) Names() []string {
fields := getFields(s.value, s.TagName)
names := make([]string, len(fields))
for i, field := range fields {
names[i] = field.Name()
}
return names
}
func getFields(v reflect.Value, tagName string) []*Field {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
var fields []*Field
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
if tag := field.Tag.Get(tagName); tag == "-" {
continue
}
f := &Field{
field: field,
value: v.FieldByName(field.Name),
}
fields = append(fields, f)
}
return fields
}
// Field returns a new Field struct that provides several high level functions
// around a single struct field entity. It panics if the field is not found.
func (s *Struct) Field(name string) *Field {
f, ok := s.FieldOk(name)
if !ok {
panic("field not found")
}
return f
}
// FieldOk returns a new Field struct that provides several high level functions
// around a single struct field entity. The boolean returns true if the field
// was found.
func (s *Struct) FieldOk(name string) (*Field, bool) {
t := s.value.Type()
field, ok := t.FieldByName(name)
if !ok {
return nil, false
}
return &Field{
field: field,
value: s.value.FieldByName(name),
defaultTag: s.TagName,
}, true
}
// IsZero returns true if all fields in a struct is a zero value (not
// initialized) A struct tag with the content of "-" ignores the checking of
// that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// A value with the option of "omitnested" stops iterating further if the type
// is a struct. Example:
//
// // Field is not processed further by this package.
// Field time.Time `structs:"myName,omitnested"`
// Field *http.Request `structs:",omitnested"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected. It panics if s's kind is not struct.
func (s *Struct) IsZero() bool {
fields := s.structFields()
for _, field := range fields {
val := s.value.FieldByName(field.Name)
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
ok := IsZero(val.Interface())
if !ok {
return false
}
continue
}
// zero value of the given field, such as "" for string, 0 for int
zero := reflect.Zero(val.Type()).Interface()
// current value of the given field
current := val.Interface()
if !reflect.DeepEqual(current, zero) {
return false
}
}
return true
}
// HasZero returns true if a field in a struct is not initialized (zero value).
// A struct tag with the content of "-" ignores the checking of that particular
// field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// A value with the option of "omitnested" stops iterating further if the type
// is a struct. Example:
//
// // Field is not processed further by this package.
// Field time.Time `structs:"myName,omitnested"`
// Field *http.Request `structs:",omitnested"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected. It panics if s's kind is not struct.
func (s *Struct) HasZero() bool {
fields := s.structFields()
for _, field := range fields {
val := s.value.FieldByName(field.Name)
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
ok := HasZero(val.Interface())
if ok {
return true
}
continue
}
// zero value of the given field, such as "" for string, 0 for int
zero := reflect.Zero(val.Type()).Interface()
// current value of the given field
current := val.Interface()
if reflect.DeepEqual(current, zero) {
return true
}
}
return false
}
// Name returns the structs's type name within its package. For more info refer
// to Name() function.
func (s *Struct) Name() string {
return s.value.Type().Name()
}
// structFields returns the exported struct fields for a given s struct. This
// is a convenient helper method to avoid duplicate code in some of the
// functions.
func (s *Struct) structFields() []reflect.StructField {
t := s.value.Type()
var f []reflect.StructField
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
// we can't access the value of unexported fields
if field.PkgPath != "" {
continue
}
// don't check if it's omitted
if tag := field.Tag.Get(s.TagName); tag == "-" {
continue
}
f = append(f, field)
}
return f
}
func strctVal(s interface{}) reflect.Value {
v := reflect.ValueOf(s)
// if pointer get the underlying element≤
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
panic("not struct")
}
return v
}
// Map converts the given struct to a map[string]interface{}. For more info
// refer to Struct types Map() method. It panics if s's kind is not struct.
func Map(s interface{}) map[string]interface{} {
return New(s).Map()
}
// FillMap is the same as Map. Instead of returning the output, it fills the
// given map.
func FillMap(s interface{}, out map[string]interface{}) {
New(s).FillMap(out)
}
// Values converts the given struct to a []interface{}. For more info refer to
// Struct types Values() method. It panics if s's kind is not struct.
func Values(s interface{}) []interface{} {
return New(s).Values()
}
// Fields returns a slice of *Field. For more info refer to Struct types
// Fields() method. It panics if s's kind is not struct.
func Fields(s interface{}) []*Field {
return New(s).Fields()
}
// Names returns a slice of field names. For more info refer to Struct types
// Names() method. It panics if s's kind is not struct.
func Names(s interface{}) []string {
return New(s).Names()
}
// IsZero returns true if all fields is equal to a zero value. For more info
// refer to Struct types IsZero() method. It panics if s's kind is not struct.
func IsZero(s interface{}) bool {
return New(s).IsZero()
}
// HasZero returns true if any field is equal to a zero value. For more info
// refer to Struct types HasZero() method. It panics if s's kind is not struct.
func HasZero(s interface{}) bool {
return New(s).HasZero()
}
// IsStruct returns true if the given variable is a struct or a pointer to
// struct.
func IsStruct(s interface{}) bool {
v := reflect.ValueOf(s)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
// uninitialized zero value of a struct
if v.Kind() == reflect.Invalid {
return false
}
return v.Kind() == reflect.Struct
}
// Name returns the structs's type name within its package. It returns an
// empty string for unnamed types. It panics if s's kind is not struct.
func Name(s interface{}) string {
return New(s).Name()
}
// nested retrieves recursively all types for the given value and returns the
// nested value.
func (s *Struct) nested(val reflect.Value) interface{} {
var finalVal interface{}
v := reflect.ValueOf(val.Interface())
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
switch v.Kind() {
case reflect.Struct:
n := New(val.Interface())
n.TagName = s.TagName
m := n.Map()
// do not add the converted value if there are no exported fields, ie:
// time.Time
if len(m) == 0 {
finalVal = val.Interface()
} else {
finalVal = m
}
case reflect.Map:
// get the element type of the map
mapElem := val.Type()
switch val.Type().Kind() {
case reflect.Ptr, reflect.Array, reflect.Map,
reflect.Slice, reflect.Chan:
mapElem = val.Type().Elem()
if mapElem.Kind() == reflect.Ptr {
mapElem = mapElem.Elem()
}
}
// only iterate over struct types, ie: map[string]StructType,
// map[string][]StructType,
if mapElem.Kind() == reflect.Struct ||
(mapElem.Kind() == reflect.Slice &&
mapElem.Elem().Kind() == reflect.Struct) {
m := make(map[string]interface{}, val.Len())
for _, k := range val.MapKeys() {
m[k.String()] = s.nested(val.MapIndex(k))
}
finalVal = m
break
}
// TODO(arslan): should this be optional?
finalVal = val.Interface()
case reflect.Slice, reflect.Array:
if val.Type().Kind() == reflect.Interface {
finalVal = val.Interface()
break
}
// TODO(arslan): should this be optional?
// do not iterate of non struct types, just pass the value. Ie: []int,
// []string, co... We only iterate further if it's a struct.
// i.e []foo or []*foo
if val.Type().Elem().Kind() != reflect.Struct &&
!(val.Type().Elem().Kind() == reflect.Ptr &&
val.Type().Elem().Elem().Kind() == reflect.Struct) {
finalVal = val.Interface()
break
}
slices := make([]interface{}, val.Len())
for x := 0; x < val.Len(); x++ {
slices[x] = s.nested(val.Index(x))
}
finalVal = slices
default:
finalVal = val.Interface()
}
return finalVal
}

View File

@ -1,32 +0,0 @@
package structs
import "strings"
// tagOptions contains a slice of tag options
type tagOptions []string
// Has returns true if the given option is available in tagOptions
func (t tagOptions) Has(opt string) bool {
for _, tagOpt := range t {
if tagOpt == opt {
return true
}
}
return false
}
// parseTag splits a struct field's tag into its name and a list of options
// which comes after a name. A tag is in the form of: "name,option1,option2".
// The name can be neglectected.
func parseTag(tag string) (string, tagOptions) {
// tag is one of followings:
// ""
// "name"
// "name,opt"
// "name,opt,opt2"
// ",opt"
res := strings.Split(tag, ",")
return res[0], res[1:]
}

View File

@ -1,8 +0,0 @@
language: go
sudo: false
go:
- 1.9.x
- 1.10.x
- 1.11.x
- tip

View File

@ -1,49 +0,0 @@
# Version 1.x.x
* **Add more test cases and reference new test COM server project.** (Placeholder for future additions)
# Version 1.2.0-alphaX
**Minimum supported version is now Go 1.4. Go 1.1 support is deprecated, but should still build.**
* Added CI configuration for Travis-CI and AppVeyor.
* Added test InterfaceID and ClassID for the COM Test Server project.
* Added more inline documentation (#83).
* Added IEnumVARIANT implementation (#88).
* Added IEnumVARIANT test cases (#99, #100, #101).
* Added support for retrieving `time.Time` from VARIANT (#92).
* Added test case for IUnknown (#64).
* Added test case for IDispatch (#64).
* Added test cases for scalar variants (#64, #76).
# Version 1.1.1
* Fixes for Linux build.
* Fixes for Windows build.
# Version 1.1.0
The change to provide building on all platforms is a new feature. The increase in minor version reflects that and allows those who wish to stay on 1.0.x to continue to do so. Support for 1.0.x will be limited to bug fixes.
* Move GUID out of variables.go into its own file to make new documentation available.
* Move OleError out of ole.go into its own file to make new documentation available.
* Add documentation to utility functions.
* Add documentation to variant receiver functions.
* Add documentation to ole structures.
* Make variant available to other systems outside of Windows.
* Make OLE structures available to other systems outside of Windows.
## New Features
* Library should now be built on all platforms supported by Go. Library will NOOP on any platform that is not Windows.
* More functions are now documented and available on godoc.org.
# Version 1.0.1
1. Fix package references from repository location change.
# Version 1.0.0
This version is stable enough for use. The COM API is still incomplete, but provides enough functionality for accessing COM servers using IDispatch interface.
There is no changelog for this version. Check commits for history.

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright © 2013-2017 Yasuhiro Matsumoto, <mattn.jp@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the “Software”), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,46 +0,0 @@
# Go OLE
[![Build status](https://ci.appveyor.com/api/projects/status/qr0u2sf7q43us9fj?svg=true)](https://ci.appveyor.com/project/jacobsantos/go-ole-jgs28)
[![Build Status](https://travis-ci.org/go-ole/go-ole.svg?branch=master)](https://travis-ci.org/go-ole/go-ole)
[![GoDoc](https://godoc.org/github.com/go-ole/go-ole?status.svg)](https://godoc.org/github.com/go-ole/go-ole)
Go bindings for Windows COM using shared libraries instead of cgo.
By Yasuhiro Matsumoto.
## Install
To experiment with go-ole, you can just compile and run the example program:
```
go get github.com/go-ole/go-ole
cd /path/to/go-ole/
go test
cd /path/to/go-ole/example/excel
go run excel.go
```
## Continuous Integration
Continuous integration configuration has been added for both Travis-CI and AppVeyor. You will have to add these to your own account for your fork in order for it to run.
**Travis-CI**
Travis-CI was added to check builds on Linux to ensure that `go get` works when cross building. Currently, Travis-CI is not used to test cross-building, but this may be changed in the future. It is also not currently possible to test the library on Linux, since COM API is specific to Windows and it is not currently possible to run a COM server on Linux or even connect to a remote COM server.
**AppVeyor**
AppVeyor is used to build on Windows using the (in-development) test COM server. It is currently only used to test the build and ensure that the code works on Windows. It will be used to register a COM server and then run the test cases based on the test COM server.
The tests currently do run and do pass and this should be maintained with commits.
## Versioning
Go OLE uses [semantic versioning](http://semver.org) for version numbers, which is similar to the version contract of the Go language. Which means that the major version will always maintain backwards compatibility with minor versions. Minor versions will only add new additions and changes. Fixes will always be in patch.
This contract should allow you to upgrade to new minor and patch versions without breakage or modifications to your existing code. Leave a ticket, if there is breakage, so that it could be fixed.
## LICENSE
Under the MIT License: http://mattn.mit-license.org/2013

View File

@ -1,54 +0,0 @@
# Notes:
# - Minimal appveyor.yml file is an empty file. All sections are optional.
# - Indent each level of configuration with 2 spaces. Do not use tabs!
# - All section names are case-sensitive.
# - Section names should be unique on each level.
version: "1.3.0.{build}-alpha-{branch}"
os: Windows Server 2012 R2
branches:
only:
- master
- v1.2
- v1.1
- v1.0
skip_tags: true
clone_folder: c:\gopath\src\github.com\go-ole\go-ole
environment:
GOPATH: c:\gopath
matrix:
- GOARCH: amd64
GOVERSION: 1.5
GOROOT: c:\go
DOWNLOADPLATFORM: "x64"
install:
- choco install mingw
- SET PATH=c:\tools\mingw64\bin;%PATH%
# - Download COM Server
- ps: Start-FileDownload "https://github.com/go-ole/test-com-server/releases/download/v1.0.2/test-com-server-${env:DOWNLOADPLATFORM}.zip"
- 7z e test-com-server-%DOWNLOADPLATFORM%.zip -oc:\gopath\src\github.com\go-ole\go-ole > NUL
- c:\gopath\src\github.com\go-ole\go-ole\build\register-assembly.bat
# - set
- go version
- go env
- go get -u golang.org/x/tools/cmd/cover
- go get -u golang.org/x/tools/cmd/godoc
- go get -u golang.org/x/tools/cmd/stringer
build_script:
- cd c:\gopath\src\github.com\go-ole\go-ole
- go get -v -t ./...
- go build
- go test -v -cover ./...
# disable automatic tests
test: off
# disable deployment
deploy: off

View File

@ -1,344 +0,0 @@
// +build windows
package ole
import (
"syscall"
"unicode/utf16"
"unsafe"
)
var (
procCoInitialize = modole32.NewProc("CoInitialize")
procCoInitializeEx = modole32.NewProc("CoInitializeEx")
procCoUninitialize = modole32.NewProc("CoUninitialize")
procCoCreateInstance = modole32.NewProc("CoCreateInstance")
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
procCLSIDFromProgID = modole32.NewProc("CLSIDFromProgID")
procCLSIDFromString = modole32.NewProc("CLSIDFromString")
procStringFromCLSID = modole32.NewProc("StringFromCLSID")
procStringFromIID = modole32.NewProc("StringFromIID")
procIIDFromString = modole32.NewProc("IIDFromString")
procCoGetObject = modole32.NewProc("CoGetObject")
procGetUserDefaultLCID = modkernel32.NewProc("GetUserDefaultLCID")
procCopyMemory = modkernel32.NewProc("RtlMoveMemory")
procVariantInit = modoleaut32.NewProc("VariantInit")
procVariantClear = modoleaut32.NewProc("VariantClear")
procVariantTimeToSystemTime = modoleaut32.NewProc("VariantTimeToSystemTime")
procSysAllocString = modoleaut32.NewProc("SysAllocString")
procSysAllocStringLen = modoleaut32.NewProc("SysAllocStringLen")
procSysFreeString = modoleaut32.NewProc("SysFreeString")
procSysStringLen = modoleaut32.NewProc("SysStringLen")
procCreateDispTypeInfo = modoleaut32.NewProc("CreateDispTypeInfo")
procCreateStdDispatch = modoleaut32.NewProc("CreateStdDispatch")
procGetActiveObject = modoleaut32.NewProc("GetActiveObject")
procGetMessageW = moduser32.NewProc("GetMessageW")
procDispatchMessageW = moduser32.NewProc("DispatchMessageW")
)
// coInitialize initializes COM library on current thread.
//
// MSDN documentation suggests that this function should not be called. Call
// CoInitializeEx() instead. The reason has to do with threading and this
// function is only for single-threaded apartments.
//
// That said, most users of the library have gotten away with just this
// function. If you are experiencing threading issues, then use
// CoInitializeEx().
func coInitialize() (err error) {
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms678543(v=vs.85).aspx
// Suggests that no value should be passed to CoInitialized.
// Could just be Call() since the parameter is optional. <-- Needs testing to be sure.
hr, _, _ := procCoInitialize.Call(uintptr(0))
if hr != 0 {
err = NewError(hr)
}
return
}
// coInitializeEx initializes COM library with concurrency model.
func coInitializeEx(coinit uint32) (err error) {
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms695279(v=vs.85).aspx
// Suggests that the first parameter is not only optional but should always be NULL.
hr, _, _ := procCoInitializeEx.Call(uintptr(0), uintptr(coinit))
if hr != 0 {
err = NewError(hr)
}
return
}
// CoInitialize initializes COM library on current thread.
//
// MSDN documentation suggests that this function should not be called. Call
// CoInitializeEx() instead. The reason has to do with threading and this
// function is only for single-threaded apartments.
//
// That said, most users of the library have gotten away with just this
// function. If you are experiencing threading issues, then use
// CoInitializeEx().
func CoInitialize(p uintptr) (err error) {
// p is ignored and won't be used.
// Avoid any variable not used errors.
p = uintptr(0)
return coInitialize()
}
// CoInitializeEx initializes COM library with concurrency model.
func CoInitializeEx(p uintptr, coinit uint32) (err error) {
// Avoid any variable not used errors.
p = uintptr(0)
return coInitializeEx(coinit)
}
// CoUninitialize uninitializes COM Library.
func CoUninitialize() {
procCoUninitialize.Call()
}
// CoTaskMemFree frees memory pointer.
func CoTaskMemFree(memptr uintptr) {
procCoTaskMemFree.Call(memptr)
}
// CLSIDFromProgID retrieves Class Identifier with the given Program Identifier.
//
// The Programmatic Identifier must be registered, because it will be looked up
// in the Windows Registry. The registry entry has the following keys: CLSID,
// Insertable, Protocol and Shell
// (https://msdn.microsoft.com/en-us/library/dd542719(v=vs.85).aspx).
//
// programID identifies the class id with less precision and is not guaranteed
// to be unique. These are usually found in the registry under
// HKEY_LOCAL_MACHINE\SOFTWARE\Classes, usually with the format of
// "Program.Component.Version" with version being optional.
//
// CLSIDFromProgID in Windows API.
func CLSIDFromProgID(progId string) (clsid *GUID, err error) {
var guid GUID
lpszProgID := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(progId)))
hr, _, _ := procCLSIDFromProgID.Call(lpszProgID, uintptr(unsafe.Pointer(&guid)))
if hr != 0 {
err = NewError(hr)
}
clsid = &guid
return
}
// CLSIDFromString retrieves Class ID from string representation.
//
// This is technically the string version of the GUID and will convert the
// string to object.
//
// CLSIDFromString in Windows API.
func CLSIDFromString(str string) (clsid *GUID, err error) {
var guid GUID
lpsz := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(str)))
hr, _, _ := procCLSIDFromString.Call(lpsz, uintptr(unsafe.Pointer(&guid)))
if hr != 0 {
err = NewError(hr)
}
clsid = &guid
return
}
// StringFromCLSID returns GUID formated string from GUID object.
func StringFromCLSID(clsid *GUID) (str string, err error) {
var p *uint16
hr, _, _ := procStringFromCLSID.Call(uintptr(unsafe.Pointer(clsid)), uintptr(unsafe.Pointer(&p)))
if hr != 0 {
err = NewError(hr)
}
str = LpOleStrToString(p)
return
}
// IIDFromString returns GUID from program ID.
func IIDFromString(progId string) (clsid *GUID, err error) {
var guid GUID
lpsz := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(progId)))
hr, _, _ := procIIDFromString.Call(lpsz, uintptr(unsafe.Pointer(&guid)))
if hr != 0 {
err = NewError(hr)
}
clsid = &guid
return
}
// StringFromIID returns GUID formatted string from GUID object.
func StringFromIID(iid *GUID) (str string, err error) {
var p *uint16
hr, _, _ := procStringFromIID.Call(uintptr(unsafe.Pointer(iid)), uintptr(unsafe.Pointer(&p)))
if hr != 0 {
err = NewError(hr)
}
str = LpOleStrToString(p)
return
}
// CreateInstance of single uninitialized object with GUID.
func CreateInstance(clsid *GUID, iid *GUID) (unk *IUnknown, err error) {
if iid == nil {
iid = IID_IUnknown
}
hr, _, _ := procCoCreateInstance.Call(
uintptr(unsafe.Pointer(clsid)),
0,
CLSCTX_SERVER,
uintptr(unsafe.Pointer(iid)),
uintptr(unsafe.Pointer(&unk)))
if hr != 0 {
err = NewError(hr)
}
return
}
// GetActiveObject retrieves pointer to active object.
func GetActiveObject(clsid *GUID, iid *GUID) (unk *IUnknown, err error) {
if iid == nil {
iid = IID_IUnknown
}
hr, _, _ := procGetActiveObject.Call(
uintptr(unsafe.Pointer(clsid)),
uintptr(unsafe.Pointer(iid)),
uintptr(unsafe.Pointer(&unk)))
if hr != 0 {
err = NewError(hr)
}
return
}
type BindOpts struct {
CbStruct uint32
GrfFlags uint32
GrfMode uint32
TickCountDeadline uint32
}
// GetObject retrieves pointer to active object.
func GetObject(programID string, bindOpts *BindOpts, iid *GUID) (unk *IUnknown, err error) {
if bindOpts != nil {
bindOpts.CbStruct = uint32(unsafe.Sizeof(BindOpts{}))
}
if iid == nil {
iid = IID_IUnknown
}
hr, _, _ := procCoGetObject.Call(
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(programID))),
uintptr(unsafe.Pointer(bindOpts)),
uintptr(unsafe.Pointer(iid)),
uintptr(unsafe.Pointer(&unk)))
if hr != 0 {
err = NewError(hr)
}
return
}
// VariantInit initializes variant.
func VariantInit(v *VARIANT) (err error) {
hr, _, _ := procVariantInit.Call(uintptr(unsafe.Pointer(v)))
if hr != 0 {
err = NewError(hr)
}
return
}
// VariantClear clears value in Variant settings to VT_EMPTY.
func VariantClear(v *VARIANT) (err error) {
hr, _, _ := procVariantClear.Call(uintptr(unsafe.Pointer(v)))
if hr != 0 {
err = NewError(hr)
}
return
}
// SysAllocString allocates memory for string and copies string into memory.
func SysAllocString(v string) (ss *int16) {
pss, _, _ := procSysAllocString.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(v))))
ss = (*int16)(unsafe.Pointer(pss))
return
}
// SysAllocStringLen copies up to length of given string returning pointer.
func SysAllocStringLen(v string) (ss *int16) {
utf16 := utf16.Encode([]rune(v + "\x00"))
ptr := &utf16[0]
pss, _, _ := procSysAllocStringLen.Call(uintptr(unsafe.Pointer(ptr)), uintptr(len(utf16)-1))
ss = (*int16)(unsafe.Pointer(pss))
return
}
// SysFreeString frees string system memory. This must be called with SysAllocString.
func SysFreeString(v *int16) (err error) {
hr, _, _ := procSysFreeString.Call(uintptr(unsafe.Pointer(v)))
if hr != 0 {
err = NewError(hr)
}
return
}
// SysStringLen is the length of the system allocated string.
func SysStringLen(v *int16) uint32 {
l, _, _ := procSysStringLen.Call(uintptr(unsafe.Pointer(v)))
return uint32(l)
}
// CreateStdDispatch provides default IDispatch implementation for IUnknown.
//
// This handles default IDispatch implementation for objects. It haves a few
// limitations with only supporting one language. It will also only return
// default exception codes.
func CreateStdDispatch(unk *IUnknown, v uintptr, ptinfo *IUnknown) (disp *IDispatch, err error) {
hr, _, _ := procCreateStdDispatch.Call(
uintptr(unsafe.Pointer(unk)),
v,
uintptr(unsafe.Pointer(ptinfo)),
uintptr(unsafe.Pointer(&disp)))
if hr != 0 {
err = NewError(hr)
}
return
}
// CreateDispTypeInfo provides default ITypeInfo implementation for IDispatch.
//
// This will not handle the full implementation of the interface.
func CreateDispTypeInfo(idata *INTERFACEDATA) (pptinfo *IUnknown, err error) {
hr, _, _ := procCreateDispTypeInfo.Call(
uintptr(unsafe.Pointer(idata)),
uintptr(GetUserDefaultLCID()),
uintptr(unsafe.Pointer(&pptinfo)))
if hr != 0 {
err = NewError(hr)
}
return
}
// copyMemory moves location of a block of memory.
func copyMemory(dest unsafe.Pointer, src unsafe.Pointer, length uint32) {
procCopyMemory.Call(uintptr(dest), uintptr(src), uintptr(length))
}
// GetUserDefaultLCID retrieves current user default locale.
func GetUserDefaultLCID() (lcid uint32) {
ret, _, _ := procGetUserDefaultLCID.Call()
lcid = uint32(ret)
return
}
// GetMessage in message queue from runtime.
//
// This function appears to block. PeekMessage does not block.
func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, err error) {
r0, _, err := procGetMessageW.Call(uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax))
ret = int32(r0)
return
}
// DispatchMessage to window procedure.
func DispatchMessage(msg *Msg) (ret int32) {
r0, _, _ := procDispatchMessageW.Call(uintptr(unsafe.Pointer(msg)))
ret = int32(r0)
return
}

View File

@ -1,174 +0,0 @@
// +build !windows
package ole
import (
"time"
"unsafe"
)
// coInitialize initializes COM library on current thread.
//
// MSDN documentation suggests that this function should not be called. Call
// CoInitializeEx() instead. The reason has to do with threading and this
// function is only for single-threaded apartments.
//
// That said, most users of the library have gotten away with just this
// function. If you are experiencing threading issues, then use
// CoInitializeEx().
func coInitialize() error {
return NewError(E_NOTIMPL)
}
// coInitializeEx initializes COM library with concurrency model.
func coInitializeEx(coinit uint32) error {
return NewError(E_NOTIMPL)
}
// CoInitialize initializes COM library on current thread.
//
// MSDN documentation suggests that this function should not be called. Call
// CoInitializeEx() instead. The reason has to do with threading and this
// function is only for single-threaded apartments.
//
// That said, most users of the library have gotten away with just this
// function. If you are experiencing threading issues, then use
// CoInitializeEx().
func CoInitialize(p uintptr) error {
return NewError(E_NOTIMPL)
}
// CoInitializeEx initializes COM library with concurrency model.
func CoInitializeEx(p uintptr, coinit uint32) error {
return NewError(E_NOTIMPL)
}
// CoUninitialize uninitializes COM Library.
func CoUninitialize() {}
// CoTaskMemFree frees memory pointer.
func CoTaskMemFree(memptr uintptr) {}
// CLSIDFromProgID retrieves Class Identifier with the given Program Identifier.
//
// The Programmatic Identifier must be registered, because it will be looked up
// in the Windows Registry. The registry entry has the following keys: CLSID,
// Insertable, Protocol and Shell
// (https://msdn.microsoft.com/en-us/library/dd542719(v=vs.85).aspx).
//
// programID identifies the class id with less precision and is not guaranteed
// to be unique. These are usually found in the registry under
// HKEY_LOCAL_MACHINE\SOFTWARE\Classes, usually with the format of
// "Program.Component.Version" with version being optional.
//
// CLSIDFromProgID in Windows API.
func CLSIDFromProgID(progId string) (*GUID, error) {
return nil, NewError(E_NOTIMPL)
}
// CLSIDFromString retrieves Class ID from string representation.
//
// This is technically the string version of the GUID and will convert the
// string to object.
//
// CLSIDFromString in Windows API.
func CLSIDFromString(str string) (*GUID, error) {
return nil, NewError(E_NOTIMPL)
}
// StringFromCLSID returns GUID formated string from GUID object.
func StringFromCLSID(clsid *GUID) (string, error) {
return "", NewError(E_NOTIMPL)
}
// IIDFromString returns GUID from program ID.
func IIDFromString(progId string) (*GUID, error) {
return nil, NewError(E_NOTIMPL)
}
// StringFromIID returns GUID formatted string from GUID object.
func StringFromIID(iid *GUID) (string, error) {
return "", NewError(E_NOTIMPL)
}
// CreateInstance of single uninitialized object with GUID.
func CreateInstance(clsid *GUID, iid *GUID) (*IUnknown, error) {
return nil, NewError(E_NOTIMPL)
}
// GetActiveObject retrieves pointer to active object.
func GetActiveObject(clsid *GUID, iid *GUID) (*IUnknown, error) {
return nil, NewError(E_NOTIMPL)
}
// VariantInit initializes variant.
func VariantInit(v *VARIANT) error {
return NewError(E_NOTIMPL)
}
// VariantClear clears value in Variant settings to VT_EMPTY.
func VariantClear(v *VARIANT) error {
return NewError(E_NOTIMPL)
}
// SysAllocString allocates memory for string and copies string into memory.
func SysAllocString(v string) *int16 {
u := int16(0)
return &u
}
// SysAllocStringLen copies up to length of given string returning pointer.
func SysAllocStringLen(v string) *int16 {
u := int16(0)
return &u
}
// SysFreeString frees string system memory. This must be called with SysAllocString.
func SysFreeString(v *int16) error {
return NewError(E_NOTIMPL)
}
// SysStringLen is the length of the system allocated string.
func SysStringLen(v *int16) uint32 {
return uint32(0)
}
// CreateStdDispatch provides default IDispatch implementation for IUnknown.
//
// This handles default IDispatch implementation for objects. It haves a few
// limitations with only supporting one language. It will also only return
// default exception codes.
func CreateStdDispatch(unk *IUnknown, v uintptr, ptinfo *IUnknown) (*IDispatch, error) {
return nil, NewError(E_NOTIMPL)
}
// CreateDispTypeInfo provides default ITypeInfo implementation for IDispatch.
//
// This will not handle the full implementation of the interface.
func CreateDispTypeInfo(idata *INTERFACEDATA) (*IUnknown, error) {
return nil, NewError(E_NOTIMPL)
}
// copyMemory moves location of a block of memory.
func copyMemory(dest unsafe.Pointer, src unsafe.Pointer, length uint32) {}
// GetUserDefaultLCID retrieves current user default locale.
func GetUserDefaultLCID() uint32 {
return uint32(0)
}
// GetMessage in message queue from runtime.
//
// This function appears to block. PeekMessage does not block.
func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (int32, error) {
return int32(0), NewError(E_NOTIMPL)
}
// DispatchMessage to window procedure.
func DispatchMessage(msg *Msg) int32 {
return int32(0)
}
func GetVariantDate(value uint64) (time.Time, error) {
return time.Now(), NewError(E_NOTIMPL)
}

View File

@ -1,192 +0,0 @@
package ole
// Connection contains IUnknown for fluent interface interaction.
//
// Deprecated. Use oleutil package instead.
type Connection struct {
Object *IUnknown // Access COM
}
// Initialize COM.
func (*Connection) Initialize() (err error) {
return coInitialize()
}
// Uninitialize COM.
func (*Connection) Uninitialize() {
CoUninitialize()
}
// Create IUnknown object based first on ProgId and then from String.
func (c *Connection) Create(progId string) (err error) {
var clsid *GUID
clsid, err = CLSIDFromProgID(progId)
if err != nil {
clsid, err = CLSIDFromString(progId)
if err != nil {
return
}
}
unknown, err := CreateInstance(clsid, IID_IUnknown)
if err != nil {
return
}
c.Object = unknown
return
}
// Release IUnknown object.
func (c *Connection) Release() {
c.Object.Release()
}
// Load COM object from list of programIDs or strings.
func (c *Connection) Load(names ...string) (errors []error) {
var tempErrors []error = make([]error, len(names))
var numErrors int = 0
for _, name := range names {
err := c.Create(name)
if err != nil {
tempErrors = append(tempErrors, err)
numErrors += 1
continue
}
break
}
copy(errors, tempErrors[0:numErrors])
return
}
// Dispatch returns Dispatch object.
func (c *Connection) Dispatch() (object *Dispatch, err error) {
dispatch, err := c.Object.QueryInterface(IID_IDispatch)
if err != nil {
return
}
object = &Dispatch{dispatch}
return
}
// Dispatch stores IDispatch object.
type Dispatch struct {
Object *IDispatch // Dispatch object.
}
// Call method on IDispatch with parameters.
func (d *Dispatch) Call(method string, params ...interface{}) (result *VARIANT, err error) {
id, err := d.GetId(method)
if err != nil {
return
}
result, err = d.Invoke(id, DISPATCH_METHOD, params)
return
}
// MustCall method on IDispatch with parameters.
func (d *Dispatch) MustCall(method string, params ...interface{}) (result *VARIANT) {
id, err := d.GetId(method)
if err != nil {
panic(err)
}
result, err = d.Invoke(id, DISPATCH_METHOD, params)
if err != nil {
panic(err)
}
return
}
// Get property on IDispatch with parameters.
func (d *Dispatch) Get(name string, params ...interface{}) (result *VARIANT, err error) {
id, err := d.GetId(name)
if err != nil {
return
}
result, err = d.Invoke(id, DISPATCH_PROPERTYGET, params)
return
}
// MustGet property on IDispatch with parameters.
func (d *Dispatch) MustGet(name string, params ...interface{}) (result *VARIANT) {
id, err := d.GetId(name)
if err != nil {
panic(err)
}
result, err = d.Invoke(id, DISPATCH_PROPERTYGET, params)
if err != nil {
panic(err)
}
return
}
// Set property on IDispatch with parameters.
func (d *Dispatch) Set(name string, params ...interface{}) (result *VARIANT, err error) {
id, err := d.GetId(name)
if err != nil {
return
}
result, err = d.Invoke(id, DISPATCH_PROPERTYPUT, params)
return
}
// MustSet property on IDispatch with parameters.
func (d *Dispatch) MustSet(name string, params ...interface{}) (result *VARIANT) {
id, err := d.GetId(name)
if err != nil {
panic(err)
}
result, err = d.Invoke(id, DISPATCH_PROPERTYPUT, params)
if err != nil {
panic(err)
}
return
}
// GetId retrieves ID of name on IDispatch.
func (d *Dispatch) GetId(name string) (id int32, err error) {
var dispid []int32
dispid, err = d.Object.GetIDsOfName([]string{name})
if err != nil {
return
}
id = dispid[0]
return
}
// GetIds retrieves all IDs of names on IDispatch.
func (d *Dispatch) GetIds(names ...string) (dispid []int32, err error) {
dispid, err = d.Object.GetIDsOfName(names)
return
}
// Invoke IDispatch on DisplayID of dispatch type with parameters.
//
// There have been problems where if send cascading params..., it would error
// out because the parameters would be empty.
func (d *Dispatch) Invoke(id int32, dispatch int16, params []interface{}) (result *VARIANT, err error) {
if len(params) < 1 {
result, err = d.Object.Invoke(id, dispatch)
} else {
result, err = d.Object.Invoke(id, dispatch, params...)
}
return
}
// Release IDispatch object.
func (d *Dispatch) Release() {
d.Object.Release()
}
// Connect initializes COM and attempts to load IUnknown based on given names.
func Connect(names ...string) (connection *Connection) {
connection.Initialize()
connection.Load(names...)
return
}

View File

@ -1,153 +0,0 @@
package ole
const (
CLSCTX_INPROC_SERVER = 1
CLSCTX_INPROC_HANDLER = 2
CLSCTX_LOCAL_SERVER = 4
CLSCTX_INPROC_SERVER16 = 8
CLSCTX_REMOTE_SERVER = 16
CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER
CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER
CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
)
const (
COINIT_APARTMENTTHREADED = 0x2
COINIT_MULTITHREADED = 0x0
COINIT_DISABLE_OLE1DDE = 0x4
COINIT_SPEED_OVER_MEMORY = 0x8
)
const (
DISPATCH_METHOD = 1
DISPATCH_PROPERTYGET = 2
DISPATCH_PROPERTYPUT = 4
DISPATCH_PROPERTYPUTREF = 8
)
const (
S_OK = 0x00000000
E_UNEXPECTED = 0x8000FFFF
E_NOTIMPL = 0x80004001
E_OUTOFMEMORY = 0x8007000E
E_INVALIDARG = 0x80070057
E_NOINTERFACE = 0x80004002
E_POINTER = 0x80004003
E_HANDLE = 0x80070006
E_ABORT = 0x80004004
E_FAIL = 0x80004005
E_ACCESSDENIED = 0x80070005
E_PENDING = 0x8000000A
CO_E_CLASSSTRING = 0x800401F3
)
const (
CC_FASTCALL = iota
CC_CDECL
CC_MSCPASCAL
CC_PASCAL = CC_MSCPASCAL
CC_MACPASCAL
CC_STDCALL
CC_FPFASTCALL
CC_SYSCALL
CC_MPWCDECL
CC_MPWPASCAL
CC_MAX = CC_MPWPASCAL
)
type VT uint16
const (
VT_EMPTY VT = 0x0
VT_NULL VT = 0x1
VT_I2 VT = 0x2
VT_I4 VT = 0x3
VT_R4 VT = 0x4
VT_R8 VT = 0x5
VT_CY VT = 0x6
VT_DATE VT = 0x7
VT_BSTR VT = 0x8
VT_DISPATCH VT = 0x9
VT_ERROR VT = 0xa
VT_BOOL VT = 0xb
VT_VARIANT VT = 0xc
VT_UNKNOWN VT = 0xd
VT_DECIMAL VT = 0xe
VT_I1 VT = 0x10
VT_UI1 VT = 0x11
VT_UI2 VT = 0x12
VT_UI4 VT = 0x13
VT_I8 VT = 0x14
VT_UI8 VT = 0x15
VT_INT VT = 0x16
VT_UINT VT = 0x17
VT_VOID VT = 0x18
VT_HRESULT VT = 0x19
VT_PTR VT = 0x1a
VT_SAFEARRAY VT = 0x1b
VT_CARRAY VT = 0x1c
VT_USERDEFINED VT = 0x1d
VT_LPSTR VT = 0x1e
VT_LPWSTR VT = 0x1f
VT_RECORD VT = 0x24
VT_INT_PTR VT = 0x25
VT_UINT_PTR VT = 0x26
VT_FILETIME VT = 0x40
VT_BLOB VT = 0x41
VT_STREAM VT = 0x42
VT_STORAGE VT = 0x43
VT_STREAMED_OBJECT VT = 0x44
VT_STORED_OBJECT VT = 0x45
VT_BLOB_OBJECT VT = 0x46
VT_CF VT = 0x47
VT_CLSID VT = 0x48
VT_BSTR_BLOB VT = 0xfff
VT_VECTOR VT = 0x1000
VT_ARRAY VT = 0x2000
VT_BYREF VT = 0x4000
VT_RESERVED VT = 0x8000
VT_ILLEGAL VT = 0xffff
VT_ILLEGALMASKED VT = 0xfff
VT_TYPEMASK VT = 0xfff
)
const (
DISPID_UNKNOWN = -1
DISPID_VALUE = 0
DISPID_PROPERTYPUT = -3
DISPID_NEWENUM = -4
DISPID_EVALUATE = -5
DISPID_CONSTRUCTOR = -6
DISPID_DESTRUCTOR = -7
DISPID_COLLECT = -8
)
const (
TKIND_ENUM = 1
TKIND_RECORD = 2
TKIND_MODULE = 3
TKIND_INTERFACE = 4
TKIND_DISPATCH = 5
TKIND_COCLASS = 6
TKIND_ALIAS = 7
TKIND_UNION = 8
TKIND_MAX = 9
)
// Safe Array Feature Flags
const (
FADF_AUTO = 0x0001
FADF_STATIC = 0x0002
FADF_EMBEDDED = 0x0004
FADF_FIXEDSIZE = 0x0010
FADF_RECORD = 0x0020
FADF_HAVEIID = 0x0040
FADF_HAVEVARTYPE = 0x0080
FADF_BSTR = 0x0100
FADF_UNKNOWN = 0x0200
FADF_DISPATCH = 0x0400
FADF_VARIANT = 0x0800
FADF_RESERVED = 0xF008
)

View File

@ -1,51 +0,0 @@
package ole
// OleError stores COM errors.
type OleError struct {
hr uintptr
description string
subError error
}
// NewError creates new error with HResult.
func NewError(hr uintptr) *OleError {
return &OleError{hr: hr}
}
// NewErrorWithDescription creates new COM error with HResult and description.
func NewErrorWithDescription(hr uintptr, description string) *OleError {
return &OleError{hr: hr, description: description}
}
// NewErrorWithSubError creates new COM error with parent error.
func NewErrorWithSubError(hr uintptr, description string, err error) *OleError {
return &OleError{hr: hr, description: description, subError: err}
}
// Code is the HResult.
func (v *OleError) Code() uintptr {
return uintptr(v.hr)
}
// String description, either manually set or format message with error code.
func (v *OleError) String() string {
if v.description != "" {
return errstr(int(v.hr)) + " (" + v.description + ")"
}
return errstr(int(v.hr))
}
// Error implements error interface.
func (v *OleError) Error() string {
return v.String()
}
// Description retrieves error summary, if there is one.
func (v *OleError) Description() string {
return v.description
}
// SubError returns parent error, if there is one.
func (v *OleError) SubError() error {
return v.subError
}

View File

@ -1,8 +0,0 @@
// +build !windows
package ole
// errstr converts error code to string.
func errstr(errno int) string {
return ""
}

View File

@ -1,24 +0,0 @@
// +build windows
package ole
import (
"fmt"
"syscall"
"unicode/utf16"
)
// errstr converts error code to string.
func errstr(errno int) string {
// ask windows for the remaining errors
var flags uint32 = syscall.FORMAT_MESSAGE_FROM_SYSTEM | syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY | syscall.FORMAT_MESSAGE_IGNORE_INSERTS
b := make([]uint16, 300)
n, err := syscall.FormatMessage(flags, 0, uint32(errno), 0, b, nil)
if err != nil {
return fmt.Sprintf("error %d (FormatMessage failed with: %v)", errno, err)
}
// trim terminating \r and \n
for ; n > 0 && (b[n-1] == '\n' || b[n-1] == '\r'); n-- {
}
return string(utf16.Decode(b[:n]))
}

View File

@ -1,5 +0,0 @@
module github.com/go-ole/go-ole
go 1.12
require golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3

View File

@ -1,2 +0,0 @@
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@ -1,284 +0,0 @@
package ole
var (
// IID_NULL is null Interface ID, used when no other Interface ID is known.
IID_NULL = NewGUID("{00000000-0000-0000-0000-000000000000}")
// IID_IUnknown is for IUnknown interfaces.
IID_IUnknown = NewGUID("{00000000-0000-0000-C000-000000000046}")
// IID_IDispatch is for IDispatch interfaces.
IID_IDispatch = NewGUID("{00020400-0000-0000-C000-000000000046}")
// IID_IEnumVariant is for IEnumVariant interfaces
IID_IEnumVariant = NewGUID("{00020404-0000-0000-C000-000000000046}")
// IID_IConnectionPointContainer is for IConnectionPointContainer interfaces.
IID_IConnectionPointContainer = NewGUID("{B196B284-BAB4-101A-B69C-00AA00341D07}")
// IID_IConnectionPoint is for IConnectionPoint interfaces.
IID_IConnectionPoint = NewGUID("{B196B286-BAB4-101A-B69C-00AA00341D07}")
// IID_IInspectable is for IInspectable interfaces.
IID_IInspectable = NewGUID("{AF86E2E0-B12D-4C6A-9C5A-D7AA65101E90}")
// IID_IProvideClassInfo is for IProvideClassInfo interfaces.
IID_IProvideClassInfo = NewGUID("{B196B283-BAB4-101A-B69C-00AA00341D07}")
)
// These are for testing and not part of any library.
var (
// IID_ICOMTestString is for ICOMTestString interfaces.
//
// {E0133EB4-C36F-469A-9D3D-C66B84BE19ED}
IID_ICOMTestString = NewGUID("{E0133EB4-C36F-469A-9D3D-C66B84BE19ED}")
// IID_ICOMTestInt8 is for ICOMTestInt8 interfaces.
//
// {BEB06610-EB84-4155-AF58-E2BFF53680B4}
IID_ICOMTestInt8 = NewGUID("{BEB06610-EB84-4155-AF58-E2BFF53680B4}")
// IID_ICOMTestInt16 is for ICOMTestInt16 interfaces.
//
// {DAA3F9FA-761E-4976-A860-8364CE55F6FC}
IID_ICOMTestInt16 = NewGUID("{DAA3F9FA-761E-4976-A860-8364CE55F6FC}")
// IID_ICOMTestInt32 is for ICOMTestInt32 interfaces.
//
// {E3DEDEE7-38A2-4540-91D1-2EEF1D8891B0}
IID_ICOMTestInt32 = NewGUID("{E3DEDEE7-38A2-4540-91D1-2EEF1D8891B0}")
// IID_ICOMTestInt64 is for ICOMTestInt64 interfaces.
//
// {8D437CBC-B3ED-485C-BC32-C336432A1623}
IID_ICOMTestInt64 = NewGUID("{8D437CBC-B3ED-485C-BC32-C336432A1623}")
// IID_ICOMTestFloat is for ICOMTestFloat interfaces.
//
// {BF1ED004-EA02-456A-AA55-2AC8AC6B054C}
IID_ICOMTestFloat = NewGUID("{BF1ED004-EA02-456A-AA55-2AC8AC6B054C}")
// IID_ICOMTestDouble is for ICOMTestDouble interfaces.
//
// {BF908A81-8687-4E93-999F-D86FAB284BA0}
IID_ICOMTestDouble = NewGUID("{BF908A81-8687-4E93-999F-D86FAB284BA0}")
// IID_ICOMTestBoolean is for ICOMTestBoolean interfaces.
//
// {D530E7A6-4EE8-40D1-8931-3D63B8605010}
IID_ICOMTestBoolean = NewGUID("{D530E7A6-4EE8-40D1-8931-3D63B8605010}")
// IID_ICOMEchoTestObject is for ICOMEchoTestObject interfaces.
//
// {6485B1EF-D780-4834-A4FE-1EBB51746CA3}
IID_ICOMEchoTestObject = NewGUID("{6485B1EF-D780-4834-A4FE-1EBB51746CA3}")
// IID_ICOMTestTypes is for ICOMTestTypes interfaces.
//
// {CCA8D7AE-91C0-4277-A8B3-FF4EDF28D3C0}
IID_ICOMTestTypes = NewGUID("{CCA8D7AE-91C0-4277-A8B3-FF4EDF28D3C0}")
// CLSID_COMEchoTestObject is for COMEchoTestObject class.
//
// {3C24506A-AE9E-4D50-9157-EF317281F1B0}
CLSID_COMEchoTestObject = NewGUID("{3C24506A-AE9E-4D50-9157-EF317281F1B0}")
// CLSID_COMTestScalarClass is for COMTestScalarClass class.
//
// {865B85C5-0334-4AC6-9EF6-AACEC8FC5E86}
CLSID_COMTestScalarClass = NewGUID("{865B85C5-0334-4AC6-9EF6-AACEC8FC5E86}")
)
const hextable = "0123456789ABCDEF"
const emptyGUID = "{00000000-0000-0000-0000-000000000000}"
// GUID is Windows API specific GUID type.
//
// This exists to match Windows GUID type for direct passing for COM.
// Format is in xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx.
type GUID struct {
Data1 uint32
Data2 uint16
Data3 uint16
Data4 [8]byte
}
// NewGUID converts the given string into a globally unique identifier that is
// compliant with the Windows API.
//
// The supplied string may be in any of these formats:
//
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
// {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
//
// The conversion of the supplied string is not case-sensitive.
func NewGUID(guid string) *GUID {
d := []byte(guid)
var d1, d2, d3, d4a, d4b []byte
switch len(d) {
case 38:
if d[0] != '{' || d[37] != '}' {
return nil
}
d = d[1:37]
fallthrough
case 36:
if d[8] != '-' || d[13] != '-' || d[18] != '-' || d[23] != '-' {
return nil
}
d1 = d[0:8]
d2 = d[9:13]
d3 = d[14:18]
d4a = d[19:23]
d4b = d[24:36]
case 32:
d1 = d[0:8]
d2 = d[8:12]
d3 = d[12:16]
d4a = d[16:20]
d4b = d[20:32]
default:
return nil
}
var g GUID
var ok1, ok2, ok3, ok4 bool
g.Data1, ok1 = decodeHexUint32(d1)
g.Data2, ok2 = decodeHexUint16(d2)
g.Data3, ok3 = decodeHexUint16(d3)
g.Data4, ok4 = decodeHexByte64(d4a, d4b)
if ok1 && ok2 && ok3 && ok4 {
return &g
}
return nil
}
func decodeHexUint32(src []byte) (value uint32, ok bool) {
var b1, b2, b3, b4 byte
var ok1, ok2, ok3, ok4 bool
b1, ok1 = decodeHexByte(src[0], src[1])
b2, ok2 = decodeHexByte(src[2], src[3])
b3, ok3 = decodeHexByte(src[4], src[5])
b4, ok4 = decodeHexByte(src[6], src[7])
value = (uint32(b1) << 24) | (uint32(b2) << 16) | (uint32(b3) << 8) | uint32(b4)
ok = ok1 && ok2 && ok3 && ok4
return
}
func decodeHexUint16(src []byte) (value uint16, ok bool) {
var b1, b2 byte
var ok1, ok2 bool
b1, ok1 = decodeHexByte(src[0], src[1])
b2, ok2 = decodeHexByte(src[2], src[3])
value = (uint16(b1) << 8) | uint16(b2)
ok = ok1 && ok2
return
}
func decodeHexByte64(s1 []byte, s2 []byte) (value [8]byte, ok bool) {
var ok1, ok2, ok3, ok4, ok5, ok6, ok7, ok8 bool
value[0], ok1 = decodeHexByte(s1[0], s1[1])
value[1], ok2 = decodeHexByte(s1[2], s1[3])
value[2], ok3 = decodeHexByte(s2[0], s2[1])
value[3], ok4 = decodeHexByte(s2[2], s2[3])
value[4], ok5 = decodeHexByte(s2[4], s2[5])
value[5], ok6 = decodeHexByte(s2[6], s2[7])
value[6], ok7 = decodeHexByte(s2[8], s2[9])
value[7], ok8 = decodeHexByte(s2[10], s2[11])
ok = ok1 && ok2 && ok3 && ok4 && ok5 && ok6 && ok7 && ok8
return
}
func decodeHexByte(c1, c2 byte) (value byte, ok bool) {
var n1, n2 byte
var ok1, ok2 bool
n1, ok1 = decodeHexChar(c1)
n2, ok2 = decodeHexChar(c2)
value = (n1 << 4) | n2
ok = ok1 && ok2
return
}
func decodeHexChar(c byte) (byte, bool) {
switch {
case '0' <= c && c <= '9':
return c - '0', true
case 'a' <= c && c <= 'f':
return c - 'a' + 10, true
case 'A' <= c && c <= 'F':
return c - 'A' + 10, true
}
return 0, false
}
// String converts the GUID to string form. It will adhere to this pattern:
//
// {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
//
// If the GUID is nil, the string representation of an empty GUID is returned:
//
// {00000000-0000-0000-0000-000000000000}
func (guid *GUID) String() string {
if guid == nil {
return emptyGUID
}
var c [38]byte
c[0] = '{'
putUint32Hex(c[1:9], guid.Data1)
c[9] = '-'
putUint16Hex(c[10:14], guid.Data2)
c[14] = '-'
putUint16Hex(c[15:19], guid.Data3)
c[19] = '-'
putByteHex(c[20:24], guid.Data4[0:2])
c[24] = '-'
putByteHex(c[25:37], guid.Data4[2:8])
c[37] = '}'
return string(c[:])
}
func putUint32Hex(b []byte, v uint32) {
b[0] = hextable[byte(v>>24)>>4]
b[1] = hextable[byte(v>>24)&0x0f]
b[2] = hextable[byte(v>>16)>>4]
b[3] = hextable[byte(v>>16)&0x0f]
b[4] = hextable[byte(v>>8)>>4]
b[5] = hextable[byte(v>>8)&0x0f]
b[6] = hextable[byte(v)>>4]
b[7] = hextable[byte(v)&0x0f]
}
func putUint16Hex(b []byte, v uint16) {
b[0] = hextable[byte(v>>8)>>4]
b[1] = hextable[byte(v>>8)&0x0f]
b[2] = hextable[byte(v)>>4]
b[3] = hextable[byte(v)&0x0f]
}
func putByteHex(dst, src []byte) {
for i := 0; i < len(src); i++ {
dst[i*2] = hextable[src[i]>>4]
dst[i*2+1] = hextable[src[i]&0x0f]
}
}
// IsEqualGUID compares two GUID.
//
// Not constant time comparison.
func IsEqualGUID(guid1 *GUID, guid2 *GUID) bool {
return guid1.Data1 == guid2.Data1 &&
guid1.Data2 == guid2.Data2 &&
guid1.Data3 == guid2.Data3 &&
guid1.Data4[0] == guid2.Data4[0] &&
guid1.Data4[1] == guid2.Data4[1] &&
guid1.Data4[2] == guid2.Data4[2] &&
guid1.Data4[3] == guid2.Data4[3] &&
guid1.Data4[4] == guid2.Data4[4] &&
guid1.Data4[5] == guid2.Data4[5] &&
guid1.Data4[6] == guid2.Data4[6] &&
guid1.Data4[7] == guid2.Data4[7]
}

View File

@ -1,20 +0,0 @@
package ole
import "unsafe"
type IConnectionPoint struct {
IUnknown
}
type IConnectionPointVtbl struct {
IUnknownVtbl
GetConnectionInterface uintptr
GetConnectionPointContainer uintptr
Advise uintptr
Unadvise uintptr
EnumConnections uintptr
}
func (v *IConnectionPoint) VTable() *IConnectionPointVtbl {
return (*IConnectionPointVtbl)(unsafe.Pointer(v.RawVTable))
}

View File

@ -1,21 +0,0 @@
// +build !windows
package ole
import "unsafe"
func (v *IConnectionPoint) GetConnectionInterface(piid **GUID) int32 {
return int32(0)
}
func (v *IConnectionPoint) Advise(unknown *IUnknown) (uint32, error) {
return uint32(0), NewError(E_NOTIMPL)
}
func (v *IConnectionPoint) Unadvise(cookie uint32) error {
return NewError(E_NOTIMPL)
}
func (v *IConnectionPoint) EnumConnections(p *unsafe.Pointer) (err error) {
return NewError(E_NOTIMPL)
}

View File

@ -1,43 +0,0 @@
// +build windows
package ole
import (
"syscall"
"unsafe"
)
func (v *IConnectionPoint) GetConnectionInterface(piid **GUID) int32 {
// XXX: This doesn't look like it does what it's supposed to
return release((*IUnknown)(unsafe.Pointer(v)))
}
func (v *IConnectionPoint) Advise(unknown *IUnknown) (cookie uint32, err error) {
hr, _, _ := syscall.Syscall(
v.VTable().Advise,
3,
uintptr(unsafe.Pointer(v)),
uintptr(unsafe.Pointer(unknown)),
uintptr(unsafe.Pointer(&cookie)))
if hr != 0 {
err = NewError(hr)
}
return
}
func (v *IConnectionPoint) Unadvise(cookie uint32) (err error) {
hr, _, _ := syscall.Syscall(
v.VTable().Unadvise,
2,
uintptr(unsafe.Pointer(v)),
uintptr(cookie),
0)
if hr != 0 {
err = NewError(hr)
}
return
}
func (v *IConnectionPoint) EnumConnections(p *unsafe.Pointer) error {
return NewError(E_NOTIMPL)
}

View File

@ -1,17 +0,0 @@
package ole
import "unsafe"
type IConnectionPointContainer struct {
IUnknown
}
type IConnectionPointContainerVtbl struct {
IUnknownVtbl
EnumConnectionPoints uintptr
FindConnectionPoint uintptr
}
func (v *IConnectionPointContainer) VTable() *IConnectionPointContainerVtbl {
return (*IConnectionPointContainerVtbl)(unsafe.Pointer(v.RawVTable))
}

View File

@ -1,11 +0,0 @@
// +build !windows
package ole
func (v *IConnectionPointContainer) EnumConnectionPoints(points interface{}) error {
return NewError(E_NOTIMPL)
}
func (v *IConnectionPointContainer) FindConnectionPoint(iid *GUID, point **IConnectionPoint) error {
return NewError(E_NOTIMPL)
}

View File

@ -1,25 +0,0 @@
// +build windows
package ole
import (
"syscall"
"unsafe"
)
func (v *IConnectionPointContainer) EnumConnectionPoints(points interface{}) error {
return NewError(E_NOTIMPL)
}
func (v *IConnectionPointContainer) FindConnectionPoint(iid *GUID, point **IConnectionPoint) (err error) {
hr, _, _ := syscall.Syscall(
v.VTable().FindConnectionPoint,
3,
uintptr(unsafe.Pointer(v)),
uintptr(unsafe.Pointer(iid)),
uintptr(unsafe.Pointer(point)))
if hr != 0 {
err = NewError(hr)
}
return
}

View File

@ -1,94 +0,0 @@
package ole
import "unsafe"
type IDispatch struct {
IUnknown
}
type IDispatchVtbl struct {
IUnknownVtbl
GetTypeInfoCount uintptr
GetTypeInfo uintptr
GetIDsOfNames uintptr
Invoke uintptr
}
func (v *IDispatch) VTable() *IDispatchVtbl {
return (*IDispatchVtbl)(unsafe.Pointer(v.RawVTable))
}
func (v *IDispatch) GetIDsOfName(names []string) (dispid []int32, err error) {
dispid, err = getIDsOfName(v, names)
return
}
func (v *IDispatch) Invoke(dispid int32, dispatch int16, params ...interface{}) (result *VARIANT, err error) {
result, err = invoke(v, dispid, dispatch, params...)
return
}
func (v *IDispatch) GetTypeInfoCount() (c uint32, err error) {
c, err = getTypeInfoCount(v)
return
}
func (v *IDispatch) GetTypeInfo() (tinfo *ITypeInfo, err error) {
tinfo, err = getTypeInfo(v)
return
}
// GetSingleIDOfName is a helper that returns single display ID for IDispatch name.
//
// This replaces the common pattern of attempting to get a single name from the list of available
// IDs. It gives the first ID, if it is available.
func (v *IDispatch) GetSingleIDOfName(name string) (displayID int32, err error) {
var displayIDs []int32
displayIDs, err = v.GetIDsOfName([]string{name})
if err != nil {
return
}
displayID = displayIDs[0]
return
}
// InvokeWithOptionalArgs accepts arguments as an array, works like Invoke.
//
// Accepts name and will attempt to retrieve Display ID to pass to Invoke.
//
// Passing params as an array is a workaround that could be fixed in later versions of Go that
// prevent passing empty params. During testing it was discovered that this is an acceptable way of
// getting around not being able to pass params normally.
func (v *IDispatch) InvokeWithOptionalArgs(name string, dispatch int16, params []interface{}) (result *VARIANT, err error) {
displayID, err := v.GetSingleIDOfName(name)
if err != nil {
return
}
if len(params) < 1 {
result, err = v.Invoke(displayID, dispatch)
} else {
result, err = v.Invoke(displayID, dispatch, params...)
}
return
}
// CallMethod invokes named function with arguments on object.
func (v *IDispatch) CallMethod(name string, params ...interface{}) (*VARIANT, error) {
return v.InvokeWithOptionalArgs(name, DISPATCH_METHOD, params)
}
// GetProperty retrieves the property with the name with the ability to pass arguments.
//
// Most of the time you will not need to pass arguments as most objects do not allow for this
// feature. Or at least, should not allow for this feature. Some servers don't follow best practices
// and this is provided for those edge cases.
func (v *IDispatch) GetProperty(name string, params ...interface{}) (*VARIANT, error) {
return v.InvokeWithOptionalArgs(name, DISPATCH_PROPERTYGET, params)
}
// PutProperty attempts to mutate a property in the object.
func (v *IDispatch) PutProperty(name string, params ...interface{}) (*VARIANT, error) {
return v.InvokeWithOptionalArgs(name, DISPATCH_PROPERTYPUT, params)
}

View File

@ -1,19 +0,0 @@
// +build !windows
package ole
func getIDsOfName(disp *IDispatch, names []string) ([]int32, error) {
return []int32{}, NewError(E_NOTIMPL)
}
func getTypeInfoCount(disp *IDispatch) (uint32, error) {
return uint32(0), NewError(E_NOTIMPL)
}
func getTypeInfo(disp *IDispatch) (*ITypeInfo, error) {
return nil, NewError(E_NOTIMPL)
}
func invoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}) (*VARIANT, error) {
return nil, NewError(E_NOTIMPL)
}

View File

@ -1,200 +0,0 @@
// +build windows
package ole
import (
"math/big"
"syscall"
"time"
"unsafe"
)
func getIDsOfName(disp *IDispatch, names []string) (dispid []int32, err error) {
wnames := make([]*uint16, len(names))
for i := 0; i < len(names); i++ {
wnames[i] = syscall.StringToUTF16Ptr(names[i])
}
dispid = make([]int32, len(names))
namelen := uint32(len(names))
hr, _, _ := syscall.Syscall6(
disp.VTable().GetIDsOfNames,
6,
uintptr(unsafe.Pointer(disp)),
uintptr(unsafe.Pointer(IID_NULL)),
uintptr(unsafe.Pointer(&wnames[0])),
uintptr(namelen),
uintptr(GetUserDefaultLCID()),
uintptr(unsafe.Pointer(&dispid[0])))
if hr != 0 {
err = NewError(hr)
}
return
}
func getTypeInfoCount(disp *IDispatch) (c uint32, err error) {
hr, _, _ := syscall.Syscall(
disp.VTable().GetTypeInfoCount,
2,
uintptr(unsafe.Pointer(disp)),
uintptr(unsafe.Pointer(&c)),
0)
if hr != 0 {
err = NewError(hr)
}
return
}
func getTypeInfo(disp *IDispatch) (tinfo *ITypeInfo, err error) {
hr, _, _ := syscall.Syscall(
disp.VTable().GetTypeInfo,
3,
uintptr(unsafe.Pointer(disp)),
uintptr(GetUserDefaultLCID()),
uintptr(unsafe.Pointer(&tinfo)))
if hr != 0 {
err = NewError(hr)
}
return
}
func invoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}) (result *VARIANT, err error) {
var dispparams DISPPARAMS
if dispatch&DISPATCH_PROPERTYPUT != 0 {
dispnames := [1]int32{DISPID_PROPERTYPUT}
dispparams.rgdispidNamedArgs = uintptr(unsafe.Pointer(&dispnames[0]))
dispparams.cNamedArgs = 1
} else if dispatch&DISPATCH_PROPERTYPUTREF != 0 {
dispnames := [1]int32{DISPID_PROPERTYPUT}
dispparams.rgdispidNamedArgs = uintptr(unsafe.Pointer(&dispnames[0]))
dispparams.cNamedArgs = 1
}
var vargs []VARIANT
if len(params) > 0 {
vargs = make([]VARIANT, len(params))
for i, v := range params {
//n := len(params)-i-1
n := len(params) - i - 1
VariantInit(&vargs[n])
switch vv := v.(type) {
case bool:
if vv {
vargs[n] = NewVariant(VT_BOOL, 0xffff)
} else {
vargs[n] = NewVariant(VT_BOOL, 0)
}
case *bool:
vargs[n] = NewVariant(VT_BOOL|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*bool)))))
case uint8:
vargs[n] = NewVariant(VT_I1, int64(v.(uint8)))
case *uint8:
vargs[n] = NewVariant(VT_I1|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint8)))))
case int8:
vargs[n] = NewVariant(VT_I1, int64(v.(int8)))
case *int8:
vargs[n] = NewVariant(VT_I1|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint8)))))
case int16:
vargs[n] = NewVariant(VT_I2, int64(v.(int16)))
case *int16:
vargs[n] = NewVariant(VT_I2|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*int16)))))
case uint16:
vargs[n] = NewVariant(VT_UI2, int64(v.(uint16)))
case *uint16:
vargs[n] = NewVariant(VT_UI2|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint16)))))
case int32:
vargs[n] = NewVariant(VT_I4, int64(v.(int32)))
case *int32:
vargs[n] = NewVariant(VT_I4|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*int32)))))
case uint32:
vargs[n] = NewVariant(VT_UI4, int64(v.(uint32)))
case *uint32:
vargs[n] = NewVariant(VT_UI4|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint32)))))
case int64:
vargs[n] = NewVariant(VT_I8, int64(v.(int64)))
case *int64:
vargs[n] = NewVariant(VT_I8|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*int64)))))
case uint64:
vargs[n] = NewVariant(VT_UI8, int64(uintptr(v.(uint64))))
case *uint64:
vargs[n] = NewVariant(VT_UI8|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint64)))))
case int:
vargs[n] = NewVariant(VT_I4, int64(v.(int)))
case *int:
vargs[n] = NewVariant(VT_I4|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*int)))))
case uint:
vargs[n] = NewVariant(VT_UI4, int64(v.(uint)))
case *uint:
vargs[n] = NewVariant(VT_UI4|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint)))))
case float32:
vargs[n] = NewVariant(VT_R4, *(*int64)(unsafe.Pointer(&vv)))
case *float32:
vargs[n] = NewVariant(VT_R4|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*float32)))))
case float64:
vargs[n] = NewVariant(VT_R8, *(*int64)(unsafe.Pointer(&vv)))
case *float64:
vargs[n] = NewVariant(VT_R8|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*float64)))))
case *big.Int:
vargs[n] = NewVariant(VT_DECIMAL, v.(*big.Int).Int64())
case string:
vargs[n] = NewVariant(VT_BSTR, int64(uintptr(unsafe.Pointer(SysAllocStringLen(v.(string))))))
case *string:
vargs[n] = NewVariant(VT_BSTR|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*string)))))
case time.Time:
s := vv.Format("2006-01-02 15:04:05")
vargs[n] = NewVariant(VT_BSTR, int64(uintptr(unsafe.Pointer(SysAllocStringLen(s)))))
case *time.Time:
s := vv.Format("2006-01-02 15:04:05")
vargs[n] = NewVariant(VT_BSTR|VT_BYREF, int64(uintptr(unsafe.Pointer(&s))))
case *IDispatch:
vargs[n] = NewVariant(VT_DISPATCH, int64(uintptr(unsafe.Pointer(v.(*IDispatch)))))
case **IDispatch:
vargs[n] = NewVariant(VT_DISPATCH|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(**IDispatch)))))
case nil:
vargs[n] = NewVariant(VT_NULL, 0)
case *VARIANT:
vargs[n] = NewVariant(VT_VARIANT|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*VARIANT)))))
case []byte:
safeByteArray := safeArrayFromByteSlice(v.([]byte))
vargs[n] = NewVariant(VT_ARRAY|VT_UI1, int64(uintptr(unsafe.Pointer(safeByteArray))))
defer VariantClear(&vargs[n])
case []string:
safeByteArray := safeArrayFromStringSlice(v.([]string))
vargs[n] = NewVariant(VT_ARRAY|VT_BSTR, int64(uintptr(unsafe.Pointer(safeByteArray))))
defer VariantClear(&vargs[n])
default:
panic("unknown type")
}
}
dispparams.rgvarg = uintptr(unsafe.Pointer(&vargs[0]))
dispparams.cArgs = uint32(len(params))
}
result = new(VARIANT)
var excepInfo EXCEPINFO
VariantInit(result)
hr, _, _ := syscall.Syscall9(
disp.VTable().Invoke,
9,
uintptr(unsafe.Pointer(disp)),
uintptr(dispid),
uintptr(unsafe.Pointer(IID_NULL)),
uintptr(GetUserDefaultLCID()),
uintptr(dispatch),
uintptr(unsafe.Pointer(&dispparams)),
uintptr(unsafe.Pointer(result)),
uintptr(unsafe.Pointer(&excepInfo)),
0)
if hr != 0 {
err = NewErrorWithSubError(hr, BstrToString(excepInfo.bstrDescription), excepInfo)
}
for i, varg := range vargs {
n := len(params) - i - 1
if varg.VT == VT_BSTR && varg.Val != 0 {
SysFreeString(((*int16)(unsafe.Pointer(uintptr(varg.Val)))))
}
if varg.VT == (VT_BSTR|VT_BYREF) && varg.Val != 0 {
*(params[n].(*string)) = LpOleStrToString(*(**uint16)(unsafe.Pointer(uintptr(varg.Val))))
}
}
return
}

View File

@ -1,19 +0,0 @@
package ole
import "unsafe"
type IEnumVARIANT struct {
IUnknown
}
type IEnumVARIANTVtbl struct {
IUnknownVtbl
Next uintptr
Skip uintptr
Reset uintptr
Clone uintptr
}
func (v *IEnumVARIANT) VTable() *IEnumVARIANTVtbl {
return (*IEnumVARIANTVtbl)(unsafe.Pointer(v.RawVTable))
}

View File

@ -1,19 +0,0 @@
// +build !windows
package ole
func (enum *IEnumVARIANT) Clone() (*IEnumVARIANT, error) {
return nil, NewError(E_NOTIMPL)
}
func (enum *IEnumVARIANT) Reset() error {
return NewError(E_NOTIMPL)
}
func (enum *IEnumVARIANT) Skip(celt uint) error {
return NewError(E_NOTIMPL)
}
func (enum *IEnumVARIANT) Next(celt uint) (VARIANT, uint, error) {
return NewVariant(VT_NULL, int64(0)), 0, NewError(E_NOTIMPL)
}

View File

@ -1,63 +0,0 @@
// +build windows
package ole
import (
"syscall"
"unsafe"
)
func (enum *IEnumVARIANT) Clone() (cloned *IEnumVARIANT, err error) {
hr, _, _ := syscall.Syscall(
enum.VTable().Clone,
2,
uintptr(unsafe.Pointer(enum)),
uintptr(unsafe.Pointer(&cloned)),
0)
if hr != 0 {
err = NewError(hr)
}
return
}
func (enum *IEnumVARIANT) Reset() (err error) {
hr, _, _ := syscall.Syscall(
enum.VTable().Reset,
1,
uintptr(unsafe.Pointer(enum)),
0,
0)
if hr != 0 {
err = NewError(hr)
}
return
}
func (enum *IEnumVARIANT) Skip(celt uint) (err error) {
hr, _, _ := syscall.Syscall(
enum.VTable().Skip,
2,
uintptr(unsafe.Pointer(enum)),
uintptr(celt),
0)
if hr != 0 {
err = NewError(hr)
}
return
}
func (enum *IEnumVARIANT) Next(celt uint) (array VARIANT, length uint, err error) {
hr, _, _ := syscall.Syscall6(
enum.VTable().Next,
4,
uintptr(unsafe.Pointer(enum)),
uintptr(celt),
uintptr(unsafe.Pointer(&array)),
uintptr(unsafe.Pointer(&length)),
0,
0)
if hr != 0 {
err = NewError(hr)
}
return
}

View File

@ -1,18 +0,0 @@
package ole
import "unsafe"
type IInspectable struct {
IUnknown
}
type IInspectableVtbl struct {
IUnknownVtbl
GetIIds uintptr
GetRuntimeClassName uintptr
GetTrustLevel uintptr
}
func (v *IInspectable) VTable() *IInspectableVtbl {
return (*IInspectableVtbl)(unsafe.Pointer(v.RawVTable))
}

View File

@ -1,15 +0,0 @@
// +build !windows
package ole
func (v *IInspectable) GetIids() ([]*GUID, error) {
return []*GUID{}, NewError(E_NOTIMPL)
}
func (v *IInspectable) GetRuntimeClassName() (string, error) {
return "", NewError(E_NOTIMPL)
}
func (v *IInspectable) GetTrustLevel() (uint32, error) {
return uint32(0), NewError(E_NOTIMPL)
}

View File

@ -1,72 +0,0 @@
// +build windows
package ole
import (
"bytes"
"encoding/binary"
"reflect"
"syscall"
"unsafe"
)
func (v *IInspectable) GetIids() (iids []*GUID, err error) {
var count uint32
var array uintptr
hr, _, _ := syscall.Syscall(
v.VTable().GetIIds,
3,
uintptr(unsafe.Pointer(v)),
uintptr(unsafe.Pointer(&count)),
uintptr(unsafe.Pointer(&array)))
if hr != 0 {
err = NewError(hr)
return
}
defer CoTaskMemFree(array)
iids = make([]*GUID, count)
byteCount := count * uint32(unsafe.Sizeof(GUID{}))
slicehdr := reflect.SliceHeader{Data: array, Len: int(byteCount), Cap: int(byteCount)}
byteSlice := *(*[]byte)(unsafe.Pointer(&slicehdr))
reader := bytes.NewReader(byteSlice)
for i := range iids {
guid := GUID{}
err = binary.Read(reader, binary.LittleEndian, &guid)
if err != nil {
return
}
iids[i] = &guid
}
return
}
func (v *IInspectable) GetRuntimeClassName() (s string, err error) {
var hstring HString
hr, _, _ := syscall.Syscall(
v.VTable().GetRuntimeClassName,
2,
uintptr(unsafe.Pointer(v)),
uintptr(unsafe.Pointer(&hstring)),
0)
if hr != 0 {
err = NewError(hr)
return
}
s = hstring.String()
DeleteHString(hstring)
return
}
func (v *IInspectable) GetTrustLevel() (level uint32, err error) {
hr, _, _ := syscall.Syscall(
v.VTable().GetTrustLevel,
2,
uintptr(unsafe.Pointer(v)),
uintptr(unsafe.Pointer(&level)),
0)
if hr != 0 {
err = NewError(hr)
}
return
}

View File

@ -1,21 +0,0 @@
package ole
import "unsafe"
type IProvideClassInfo struct {
IUnknown
}
type IProvideClassInfoVtbl struct {
IUnknownVtbl
GetClassInfo uintptr
}
func (v *IProvideClassInfo) VTable() *IProvideClassInfoVtbl {
return (*IProvideClassInfoVtbl)(unsafe.Pointer(v.RawVTable))
}
func (v *IProvideClassInfo) GetClassInfo() (cinfo *ITypeInfo, err error) {
cinfo, err = getClassInfo(v)
return
}

View File

@ -1,7 +0,0 @@
// +build !windows
package ole
func getClassInfo(disp *IProvideClassInfo) (tinfo *ITypeInfo, err error) {
return nil, NewError(E_NOTIMPL)
}

View File

@ -1,21 +0,0 @@
// +build windows
package ole
import (
"syscall"
"unsafe"
)
func getClassInfo(disp *IProvideClassInfo) (tinfo *ITypeInfo, err error) {
hr, _, _ := syscall.Syscall(
disp.VTable().GetClassInfo,
2,
uintptr(unsafe.Pointer(disp)),
uintptr(unsafe.Pointer(&tinfo)),
0)
if hr != 0 {
err = NewError(hr)
}
return
}

View File

@ -1,34 +0,0 @@
package ole
import "unsafe"
type ITypeInfo struct {
IUnknown
}
type ITypeInfoVtbl struct {
IUnknownVtbl
GetTypeAttr uintptr
GetTypeComp uintptr
GetFuncDesc uintptr
GetVarDesc uintptr
GetNames uintptr
GetRefTypeOfImplType uintptr
GetImplTypeFlags uintptr
GetIDsOfNames uintptr
Invoke uintptr
GetDocumentation uintptr
GetDllEntry uintptr
GetRefTypeInfo uintptr
AddressOfMember uintptr
CreateInstance uintptr
GetMops uintptr
GetContainingTypeLib uintptr
ReleaseTypeAttr uintptr
ReleaseFuncDesc uintptr
ReleaseVarDesc uintptr
}
func (v *ITypeInfo) VTable() *ITypeInfoVtbl {
return (*ITypeInfoVtbl)(unsafe.Pointer(v.RawVTable))
}

View File

@ -1,7 +0,0 @@
// +build !windows
package ole
func (v *ITypeInfo) GetTypeAttr() (*TYPEATTR, error) {
return nil, NewError(E_NOTIMPL)
}

View File

@ -1,21 +0,0 @@
// +build windows
package ole
import (
"syscall"
"unsafe"
)
func (v *ITypeInfo) GetTypeAttr() (tattr *TYPEATTR, err error) {
hr, _, _ := syscall.Syscall(
uintptr(v.VTable().GetTypeAttr),
2,
uintptr(unsafe.Pointer(v)),
uintptr(unsafe.Pointer(&tattr)),
0)
if hr != 0 {
err = NewError(hr)
}
return
}

View File

@ -1,57 +0,0 @@
package ole
import "unsafe"
type IUnknown struct {
RawVTable *interface{}
}
type IUnknownVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
}
type UnknownLike interface {
QueryInterface(iid *GUID) (disp *IDispatch, err error)
AddRef() int32
Release() int32
}
func (v *IUnknown) VTable() *IUnknownVtbl {
return (*IUnknownVtbl)(unsafe.Pointer(v.RawVTable))
}
func (v *IUnknown) PutQueryInterface(interfaceID *GUID, obj interface{}) error {
return reflectQueryInterface(v, v.VTable().QueryInterface, interfaceID, obj)
}
func (v *IUnknown) IDispatch(interfaceID *GUID) (dispatch *IDispatch, err error) {
err = v.PutQueryInterface(interfaceID, &dispatch)
return
}
func (v *IUnknown) IEnumVARIANT(interfaceID *GUID) (enum *IEnumVARIANT, err error) {
err = v.PutQueryInterface(interfaceID, &enum)
return
}
func (v *IUnknown) QueryInterface(iid *GUID) (*IDispatch, error) {
return queryInterface(v, iid)
}
func (v *IUnknown) MustQueryInterface(iid *GUID) (disp *IDispatch) {
unk, err := queryInterface(v, iid)
if err != nil {
panic(err)
}
return unk
}
func (v *IUnknown) AddRef() int32 {
return addRef(v)
}
func (v *IUnknown) Release() int32 {
return release(v)
}

View File

@ -1,19 +0,0 @@
// +build !windows
package ole
func reflectQueryInterface(self interface{}, method uintptr, interfaceID *GUID, obj interface{}) (err error) {
return NewError(E_NOTIMPL)
}
func queryInterface(unk *IUnknown, iid *GUID) (disp *IDispatch, err error) {
return nil, NewError(E_NOTIMPL)
}
func addRef(unk *IUnknown) int32 {
return 0
}
func release(unk *IUnknown) int32 {
return 0
}

View File

@ -1,58 +0,0 @@
// +build windows
package ole
import (
"reflect"
"syscall"
"unsafe"
)
func reflectQueryInterface(self interface{}, method uintptr, interfaceID *GUID, obj interface{}) (err error) {
selfValue := reflect.ValueOf(self).Elem()
objValue := reflect.ValueOf(obj).Elem()
hr, _, _ := syscall.Syscall(
method,
3,
selfValue.UnsafeAddr(),
uintptr(unsafe.Pointer(interfaceID)),
objValue.Addr().Pointer())
if hr != 0 {
err = NewError(hr)
}
return
}
func queryInterface(unk *IUnknown, iid *GUID) (disp *IDispatch, err error) {
hr, _, _ := syscall.Syscall(
unk.VTable().QueryInterface,
3,
uintptr(unsafe.Pointer(unk)),
uintptr(unsafe.Pointer(iid)),
uintptr(unsafe.Pointer(&disp)))
if hr != 0 {
err = NewError(hr)
}
return
}
func addRef(unk *IUnknown) int32 {
ret, _, _ := syscall.Syscall(
unk.VTable().AddRef,
1,
uintptr(unsafe.Pointer(unk)),
0,
0)
return int32(ret)
}
func release(unk *IUnknown) int32 {
ret, _, _ := syscall.Syscall(
unk.VTable().Release,
1,
uintptr(unsafe.Pointer(unk)),
0,
0)
return int32(ret)
}

View File

@ -1,157 +0,0 @@
package ole
import (
"fmt"
"strings"
)
// DISPPARAMS are the arguments that passed to methods or property.
type DISPPARAMS struct {
rgvarg uintptr
rgdispidNamedArgs uintptr
cArgs uint32
cNamedArgs uint32
}
// EXCEPINFO defines exception info.
type EXCEPINFO struct {
wCode uint16
wReserved uint16
bstrSource *uint16
bstrDescription *uint16
bstrHelpFile *uint16
dwHelpContext uint32
pvReserved uintptr
pfnDeferredFillIn uintptr
scode uint32
}
// WCode return wCode in EXCEPINFO.
func (e EXCEPINFO) WCode() uint16 {
return e.wCode
}
// SCODE return scode in EXCEPINFO.
func (e EXCEPINFO) SCODE() uint32 {
return e.scode
}
// String convert EXCEPINFO to string.
func (e EXCEPINFO) String() string {
var src, desc, hlp string
if e.bstrSource == nil {
src = "<nil>"
} else {
src = BstrToString(e.bstrSource)
}
if e.bstrDescription == nil {
desc = "<nil>"
} else {
desc = BstrToString(e.bstrDescription)
}
if e.bstrHelpFile == nil {
hlp = "<nil>"
} else {
hlp = BstrToString(e.bstrHelpFile)
}
return fmt.Sprintf(
"wCode: %#x, bstrSource: %v, bstrDescription: %v, bstrHelpFile: %v, dwHelpContext: %#x, scode: %#x",
e.wCode, src, desc, hlp, e.dwHelpContext, e.scode,
)
}
// Error implements error interface and returns error string.
func (e EXCEPINFO) Error() string {
if e.bstrDescription != nil {
return strings.TrimSpace(BstrToString(e.bstrDescription))
}
src := "Unknown"
if e.bstrSource != nil {
src = BstrToString(e.bstrSource)
}
code := e.scode
if e.wCode != 0 {
code = uint32(e.wCode)
}
return fmt.Sprintf("%v: %#x", src, code)
}
// PARAMDATA defines parameter data type.
type PARAMDATA struct {
Name *int16
Vt uint16
}
// METHODDATA defines method info.
type METHODDATA struct {
Name *uint16
Data *PARAMDATA
Dispid int32
Meth uint32
CC int32
CArgs uint32
Flags uint16
VtReturn uint32
}
// INTERFACEDATA defines interface info.
type INTERFACEDATA struct {
MethodData *METHODDATA
CMembers uint32
}
// Point is 2D vector type.
type Point struct {
X int32
Y int32
}
// Msg is message between processes.
type Msg struct {
Hwnd uint32
Message uint32
Wparam int32
Lparam int32
Time uint32
Pt Point
}
// TYPEDESC defines data type.
type TYPEDESC struct {
Hreftype uint32
VT uint16
}
// IDLDESC defines IDL info.
type IDLDESC struct {
DwReserved uint32
WIDLFlags uint16
}
// TYPEATTR defines type info.
type TYPEATTR struct {
Guid GUID
Lcid uint32
dwReserved uint32
MemidConstructor int32
MemidDestructor int32
LpstrSchema *uint16
CbSizeInstance uint32
Typekind int32
CFuncs uint16
CVars uint16
CImplTypes uint16
CbSizeVft uint16
CbAlignment uint16
WTypeFlags uint16
WMajorVerNum uint16
WMinorVerNum uint16
TdescAlias TYPEDESC
IdldescType IDLDESC
}

View File

@ -1,27 +0,0 @@
// Package is meant to retrieve and process safe array data returned from COM.
package ole
// SafeArrayBound defines the SafeArray boundaries.
type SafeArrayBound struct {
Elements uint32
LowerBound int32
}
// SafeArray is how COM handles arrays.
type SafeArray struct {
Dimensions uint16
FeaturesFlag uint16
ElementsSize uint32
LocksAmount uint32
Data uint32
Bounds [16]byte
}
// SAFEARRAY is obsolete, exists for backwards compatibility.
// Use SafeArray
type SAFEARRAY SafeArray
// SAFEARRAYBOUND is obsolete, exists for backwards compatibility.
// Use SafeArrayBound
type SAFEARRAYBOUND SafeArrayBound

View File

@ -1,211 +0,0 @@
// +build !windows
package ole
import (
"unsafe"
)
// safeArrayAccessData returns raw array pointer.
//
// AKA: SafeArrayAccessData in Windows API.
func safeArrayAccessData(safearray *SafeArray) (uintptr, error) {
return uintptr(0), NewError(E_NOTIMPL)
}
// safeArrayUnaccessData releases raw array.
//
// AKA: SafeArrayUnaccessData in Windows API.
func safeArrayUnaccessData(safearray *SafeArray) error {
return NewError(E_NOTIMPL)
}
// safeArrayAllocData allocates SafeArray.
//
// AKA: SafeArrayAllocData in Windows API.
func safeArrayAllocData(safearray *SafeArray) error {
return NewError(E_NOTIMPL)
}
// safeArrayAllocDescriptor allocates SafeArray.
//
// AKA: SafeArrayAllocDescriptor in Windows API.
func safeArrayAllocDescriptor(dimensions uint32) (*SafeArray, error) {
return nil, NewError(E_NOTIMPL)
}
// safeArrayAllocDescriptorEx allocates SafeArray.
//
// AKA: SafeArrayAllocDescriptorEx in Windows API.
func safeArrayAllocDescriptorEx(variantType VT, dimensions uint32) (*SafeArray, error) {
return nil, NewError(E_NOTIMPL)
}
// safeArrayCopy returns copy of SafeArray.
//
// AKA: SafeArrayCopy in Windows API.
func safeArrayCopy(original *SafeArray) (*SafeArray, error) {
return nil, NewError(E_NOTIMPL)
}
// safeArrayCopyData duplicates SafeArray into another SafeArray object.
//
// AKA: SafeArrayCopyData in Windows API.
func safeArrayCopyData(original *SafeArray, duplicate *SafeArray) error {
return NewError(E_NOTIMPL)
}
// safeArrayCreate creates SafeArray.
//
// AKA: SafeArrayCreate in Windows API.
func safeArrayCreate(variantType VT, dimensions uint32, bounds *SafeArrayBound) (*SafeArray, error) {
return nil, NewError(E_NOTIMPL)
}
// safeArrayCreateEx creates SafeArray.
//
// AKA: SafeArrayCreateEx in Windows API.
func safeArrayCreateEx(variantType VT, dimensions uint32, bounds *SafeArrayBound, extra uintptr) (*SafeArray, error) {
return nil, NewError(E_NOTIMPL)
}
// safeArrayCreateVector creates SafeArray.
//
// AKA: SafeArrayCreateVector in Windows API.
func safeArrayCreateVector(variantType VT, lowerBound int32, length uint32) (*SafeArray, error) {
return nil, NewError(E_NOTIMPL)
}
// safeArrayCreateVectorEx creates SafeArray.
//
// AKA: SafeArrayCreateVectorEx in Windows API.
func safeArrayCreateVectorEx(variantType VT, lowerBound int32, length uint32, extra uintptr) (*SafeArray, error) {
return nil, NewError(E_NOTIMPL)
}
// safeArrayDestroy destroys SafeArray object.
//
// AKA: SafeArrayDestroy in Windows API.
func safeArrayDestroy(safearray *SafeArray) error {
return NewError(E_NOTIMPL)
}
// safeArrayDestroyData destroys SafeArray object.
//
// AKA: SafeArrayDestroyData in Windows API.
func safeArrayDestroyData(safearray *SafeArray) error {
return NewError(E_NOTIMPL)
}
// safeArrayDestroyDescriptor destroys SafeArray object.
//
// AKA: SafeArrayDestroyDescriptor in Windows API.
func safeArrayDestroyDescriptor(safearray *SafeArray) error {
return NewError(E_NOTIMPL)
}
// safeArrayGetDim is the amount of dimensions in the SafeArray.
//
// SafeArrays may have multiple dimensions. Meaning, it could be
// multidimensional array.
//
// AKA: SafeArrayGetDim in Windows API.
func safeArrayGetDim(safearray *SafeArray) (*uint32, error) {
u := uint32(0)
return &u, NewError(E_NOTIMPL)
}
// safeArrayGetElementSize is the element size in bytes.
//
// AKA: SafeArrayGetElemsize in Windows API.
func safeArrayGetElementSize(safearray *SafeArray) (*uint32, error) {
u := uint32(0)
return &u, NewError(E_NOTIMPL)
}
// safeArrayGetElement retrieves element at given index.
func safeArrayGetElement(safearray *SafeArray, index int32, pv unsafe.Pointer) error {
return NewError(E_NOTIMPL)
}
// safeArrayGetElement retrieves element at given index and converts to string.
func safeArrayGetElementString(safearray *SafeArray, index int32) (string, error) {
return "", NewError(E_NOTIMPL)
}
// safeArrayGetIID is the InterfaceID of the elements in the SafeArray.
//
// AKA: SafeArrayGetIID in Windows API.
func safeArrayGetIID(safearray *SafeArray) (*GUID, error) {
return nil, NewError(E_NOTIMPL)
}
// safeArrayGetLBound returns lower bounds of SafeArray.
//
// SafeArrays may have multiple dimensions. Meaning, it could be
// multidimensional array.
//
// AKA: SafeArrayGetLBound in Windows API.
func safeArrayGetLBound(safearray *SafeArray, dimension uint32) (int32, error) {
return int32(0), NewError(E_NOTIMPL)
}
// safeArrayGetUBound returns upper bounds of SafeArray.
//
// SafeArrays may have multiple dimensions. Meaning, it could be
// multidimensional array.
//
// AKA: SafeArrayGetUBound in Windows API.
func safeArrayGetUBound(safearray *SafeArray, dimension uint32) (int32, error) {
return int32(0), NewError(E_NOTIMPL)
}
// safeArrayGetVartype returns data type of SafeArray.
//
// AKA: SafeArrayGetVartype in Windows API.
func safeArrayGetVartype(safearray *SafeArray) (uint16, error) {
return uint16(0), NewError(E_NOTIMPL)
}
// safeArrayLock locks SafeArray for reading to modify SafeArray.
//
// This must be called during some calls to ensure that another process does not
// read or write to the SafeArray during editing.
//
// AKA: SafeArrayLock in Windows API.
func safeArrayLock(safearray *SafeArray) error {
return NewError(E_NOTIMPL)
}
// safeArrayUnlock unlocks SafeArray for reading.
//
// AKA: SafeArrayUnlock in Windows API.
func safeArrayUnlock(safearray *SafeArray) error {
return NewError(E_NOTIMPL)
}
// safeArrayPutElement stores the data element at the specified location in the
// array.
//
// AKA: SafeArrayPutElement in Windows API.
func safeArrayPutElement(safearray *SafeArray, index int64, element uintptr) error {
return NewError(E_NOTIMPL)
}
// safeArrayGetRecordInfo accesses IRecordInfo info for custom types.
//
// AKA: SafeArrayGetRecordInfo in Windows API.
//
// XXX: Must implement IRecordInfo interface for this to return.
func safeArrayGetRecordInfo(safearray *SafeArray) (interface{}, error) {
return nil, NewError(E_NOTIMPL)
}
// safeArraySetRecordInfo mutates IRecordInfo info for custom types.
//
// AKA: SafeArraySetRecordInfo in Windows API.
//
// XXX: Must implement IRecordInfo interface for this to return.
func safeArraySetRecordInfo(safearray *SafeArray, recordInfo interface{}) error {
return NewError(E_NOTIMPL)
}

View File

@ -1,337 +0,0 @@
// +build windows
package ole
import (
"unsafe"
)
var (
procSafeArrayAccessData = modoleaut32.NewProc("SafeArrayAccessData")
procSafeArrayAllocData = modoleaut32.NewProc("SafeArrayAllocData")
procSafeArrayAllocDescriptor = modoleaut32.NewProc("SafeArrayAllocDescriptor")
procSafeArrayAllocDescriptorEx = modoleaut32.NewProc("SafeArrayAllocDescriptorEx")
procSafeArrayCopy = modoleaut32.NewProc("SafeArrayCopy")
procSafeArrayCopyData = modoleaut32.NewProc("SafeArrayCopyData")
procSafeArrayCreate = modoleaut32.NewProc("SafeArrayCreate")
procSafeArrayCreateEx = modoleaut32.NewProc("SafeArrayCreateEx")
procSafeArrayCreateVector = modoleaut32.NewProc("SafeArrayCreateVector")
procSafeArrayCreateVectorEx = modoleaut32.NewProc("SafeArrayCreateVectorEx")
procSafeArrayDestroy = modoleaut32.NewProc("SafeArrayDestroy")
procSafeArrayDestroyData = modoleaut32.NewProc("SafeArrayDestroyData")
procSafeArrayDestroyDescriptor = modoleaut32.NewProc("SafeArrayDestroyDescriptor")
procSafeArrayGetDim = modoleaut32.NewProc("SafeArrayGetDim")
procSafeArrayGetElement = modoleaut32.NewProc("SafeArrayGetElement")
procSafeArrayGetElemsize = modoleaut32.NewProc("SafeArrayGetElemsize")
procSafeArrayGetIID = modoleaut32.NewProc("SafeArrayGetIID")
procSafeArrayGetLBound = modoleaut32.NewProc("SafeArrayGetLBound")
procSafeArrayGetUBound = modoleaut32.NewProc("SafeArrayGetUBound")
procSafeArrayGetVartype = modoleaut32.NewProc("SafeArrayGetVartype")
procSafeArrayLock = modoleaut32.NewProc("SafeArrayLock")
procSafeArrayPtrOfIndex = modoleaut32.NewProc("SafeArrayPtrOfIndex")
procSafeArrayUnaccessData = modoleaut32.NewProc("SafeArrayUnaccessData")
procSafeArrayUnlock = modoleaut32.NewProc("SafeArrayUnlock")
procSafeArrayPutElement = modoleaut32.NewProc("SafeArrayPutElement")
//procSafeArrayRedim = modoleaut32.NewProc("SafeArrayRedim") // TODO
//procSafeArraySetIID = modoleaut32.NewProc("SafeArraySetIID") // TODO
procSafeArrayGetRecordInfo = modoleaut32.NewProc("SafeArrayGetRecordInfo")
procSafeArraySetRecordInfo = modoleaut32.NewProc("SafeArraySetRecordInfo")
)
// safeArrayAccessData returns raw array pointer.
//
// AKA: SafeArrayAccessData in Windows API.
// Todo: Test
func safeArrayAccessData(safearray *SafeArray) (element uintptr, err error) {
err = convertHresultToError(
procSafeArrayAccessData.Call(
uintptr(unsafe.Pointer(safearray)),
uintptr(unsafe.Pointer(&element))))
return
}
// safeArrayUnaccessData releases raw array.
//
// AKA: SafeArrayUnaccessData in Windows API.
func safeArrayUnaccessData(safearray *SafeArray) (err error) {
err = convertHresultToError(procSafeArrayUnaccessData.Call(uintptr(unsafe.Pointer(safearray))))
return
}
// safeArrayAllocData allocates SafeArray.
//
// AKA: SafeArrayAllocData in Windows API.
func safeArrayAllocData(safearray *SafeArray) (err error) {
err = convertHresultToError(procSafeArrayAllocData.Call(uintptr(unsafe.Pointer(safearray))))
return
}
// safeArrayAllocDescriptor allocates SafeArray.
//
// AKA: SafeArrayAllocDescriptor in Windows API.
func safeArrayAllocDescriptor(dimensions uint32) (safearray *SafeArray, err error) {
err = convertHresultToError(
procSafeArrayAllocDescriptor.Call(uintptr(dimensions), uintptr(unsafe.Pointer(&safearray))))
return
}
// safeArrayAllocDescriptorEx allocates SafeArray.
//
// AKA: SafeArrayAllocDescriptorEx in Windows API.
func safeArrayAllocDescriptorEx(variantType VT, dimensions uint32) (safearray *SafeArray, err error) {
err = convertHresultToError(
procSafeArrayAllocDescriptorEx.Call(
uintptr(variantType),
uintptr(dimensions),
uintptr(unsafe.Pointer(&safearray))))
return
}
// safeArrayCopy returns copy of SafeArray.
//
// AKA: SafeArrayCopy in Windows API.
func safeArrayCopy(original *SafeArray) (safearray *SafeArray, err error) {
err = convertHresultToError(
procSafeArrayCopy.Call(
uintptr(unsafe.Pointer(original)),
uintptr(unsafe.Pointer(&safearray))))
return
}
// safeArrayCopyData duplicates SafeArray into another SafeArray object.
//
// AKA: SafeArrayCopyData in Windows API.
func safeArrayCopyData(original *SafeArray, duplicate *SafeArray) (err error) {
err = convertHresultToError(
procSafeArrayCopyData.Call(
uintptr(unsafe.Pointer(original)),
uintptr(unsafe.Pointer(duplicate))))
return
}
// safeArrayCreate creates SafeArray.
//
// AKA: SafeArrayCreate in Windows API.
func safeArrayCreate(variantType VT, dimensions uint32, bounds *SafeArrayBound) (safearray *SafeArray, err error) {
sa, _, err := procSafeArrayCreate.Call(
uintptr(variantType),
uintptr(dimensions),
uintptr(unsafe.Pointer(bounds)))
safearray = (*SafeArray)(unsafe.Pointer(&sa))
return
}
// safeArrayCreateEx creates SafeArray.
//
// AKA: SafeArrayCreateEx in Windows API.
func safeArrayCreateEx(variantType VT, dimensions uint32, bounds *SafeArrayBound, extra uintptr) (safearray *SafeArray, err error) {
sa, _, err := procSafeArrayCreateEx.Call(
uintptr(variantType),
uintptr(dimensions),
uintptr(unsafe.Pointer(bounds)),
extra)
safearray = (*SafeArray)(unsafe.Pointer(sa))
return
}
// safeArrayCreateVector creates SafeArray.
//
// AKA: SafeArrayCreateVector in Windows API.
func safeArrayCreateVector(variantType VT, lowerBound int32, length uint32) (safearray *SafeArray, err error) {
sa, _, err := procSafeArrayCreateVector.Call(
uintptr(variantType),
uintptr(lowerBound),
uintptr(length))
safearray = (*SafeArray)(unsafe.Pointer(sa))
return
}
// safeArrayCreateVectorEx creates SafeArray.
//
// AKA: SafeArrayCreateVectorEx in Windows API.
func safeArrayCreateVectorEx(variantType VT, lowerBound int32, length uint32, extra uintptr) (safearray *SafeArray, err error) {
sa, _, err := procSafeArrayCreateVectorEx.Call(
uintptr(variantType),
uintptr(lowerBound),
uintptr(length),
extra)
safearray = (*SafeArray)(unsafe.Pointer(sa))
return
}
// safeArrayDestroy destroys SafeArray object.
//
// AKA: SafeArrayDestroy in Windows API.
func safeArrayDestroy(safearray *SafeArray) (err error) {
err = convertHresultToError(procSafeArrayDestroy.Call(uintptr(unsafe.Pointer(safearray))))
return
}
// safeArrayDestroyData destroys SafeArray object.
//
// AKA: SafeArrayDestroyData in Windows API.
func safeArrayDestroyData(safearray *SafeArray) (err error) {
err = convertHresultToError(procSafeArrayDestroyData.Call(uintptr(unsafe.Pointer(safearray))))
return
}
// safeArrayDestroyDescriptor destroys SafeArray object.
//
// AKA: SafeArrayDestroyDescriptor in Windows API.
func safeArrayDestroyDescriptor(safearray *SafeArray) (err error) {
err = convertHresultToError(procSafeArrayDestroyDescriptor.Call(uintptr(unsafe.Pointer(safearray))))
return
}
// safeArrayGetDim is the amount of dimensions in the SafeArray.
//
// SafeArrays may have multiple dimensions. Meaning, it could be
// multidimensional array.
//
// AKA: SafeArrayGetDim in Windows API.
func safeArrayGetDim(safearray *SafeArray) (dimensions *uint32, err error) {
l, _, err := procSafeArrayGetDim.Call(uintptr(unsafe.Pointer(safearray)))
dimensions = (*uint32)(unsafe.Pointer(l))
return
}
// safeArrayGetElementSize is the element size in bytes.
//
// AKA: SafeArrayGetElemsize in Windows API.
func safeArrayGetElementSize(safearray *SafeArray) (length *uint32, err error) {
l, _, err := procSafeArrayGetElemsize.Call(uintptr(unsafe.Pointer(safearray)))
length = (*uint32)(unsafe.Pointer(l))
return
}
// safeArrayGetElement retrieves element at given index.
func safeArrayGetElement(safearray *SafeArray, index int32, pv unsafe.Pointer) error {
return convertHresultToError(
procSafeArrayGetElement.Call(
uintptr(unsafe.Pointer(safearray)),
uintptr(unsafe.Pointer(&index)),
uintptr(pv)))
}
// safeArrayGetElementString retrieves element at given index and converts to string.
func safeArrayGetElementString(safearray *SafeArray, index int32) (str string, err error) {
var element *int16
err = convertHresultToError(
procSafeArrayGetElement.Call(
uintptr(unsafe.Pointer(safearray)),
uintptr(unsafe.Pointer(&index)),
uintptr(unsafe.Pointer(&element))))
str = BstrToString(*(**uint16)(unsafe.Pointer(&element)))
SysFreeString(element)
return
}
// safeArrayGetIID is the InterfaceID of the elements in the SafeArray.
//
// AKA: SafeArrayGetIID in Windows API.
func safeArrayGetIID(safearray *SafeArray) (guid *GUID, err error) {
err = convertHresultToError(
procSafeArrayGetIID.Call(
uintptr(unsafe.Pointer(safearray)),
uintptr(unsafe.Pointer(&guid))))
return
}
// safeArrayGetLBound returns lower bounds of SafeArray.
//
// SafeArrays may have multiple dimensions. Meaning, it could be
// multidimensional array.
//
// AKA: SafeArrayGetLBound in Windows API.
func safeArrayGetLBound(safearray *SafeArray, dimension uint32) (lowerBound int32, err error) {
err = convertHresultToError(
procSafeArrayGetLBound.Call(
uintptr(unsafe.Pointer(safearray)),
uintptr(dimension),
uintptr(unsafe.Pointer(&lowerBound))))
return
}
// safeArrayGetUBound returns upper bounds of SafeArray.
//
// SafeArrays may have multiple dimensions. Meaning, it could be
// multidimensional array.
//
// AKA: SafeArrayGetUBound in Windows API.
func safeArrayGetUBound(safearray *SafeArray, dimension uint32) (upperBound int32, err error) {
err = convertHresultToError(
procSafeArrayGetUBound.Call(
uintptr(unsafe.Pointer(safearray)),
uintptr(dimension),
uintptr(unsafe.Pointer(&upperBound))))
return
}
// safeArrayGetVartype returns data type of SafeArray.
//
// AKA: SafeArrayGetVartype in Windows API.
func safeArrayGetVartype(safearray *SafeArray) (varType uint16, err error) {
err = convertHresultToError(
procSafeArrayGetVartype.Call(
uintptr(unsafe.Pointer(safearray)),
uintptr(unsafe.Pointer(&varType))))
return
}
// safeArrayLock locks SafeArray for reading to modify SafeArray.
//
// This must be called during some calls to ensure that another process does not
// read or write to the SafeArray during editing.
//
// AKA: SafeArrayLock in Windows API.
func safeArrayLock(safearray *SafeArray) (err error) {
err = convertHresultToError(procSafeArrayLock.Call(uintptr(unsafe.Pointer(safearray))))
return
}
// safeArrayUnlock unlocks SafeArray for reading.
//
// AKA: SafeArrayUnlock in Windows API.
func safeArrayUnlock(safearray *SafeArray) (err error) {
err = convertHresultToError(procSafeArrayUnlock.Call(uintptr(unsafe.Pointer(safearray))))
return
}
// safeArrayPutElement stores the data element at the specified location in the
// array.
//
// AKA: SafeArrayPutElement in Windows API.
func safeArrayPutElement(safearray *SafeArray, index int64, element uintptr) (err error) {
err = convertHresultToError(
procSafeArrayPutElement.Call(
uintptr(unsafe.Pointer(safearray)),
uintptr(unsafe.Pointer(&index)),
uintptr(unsafe.Pointer(element))))
return
}
// safeArrayGetRecordInfo accesses IRecordInfo info for custom types.
//
// AKA: SafeArrayGetRecordInfo in Windows API.
//
// XXX: Must implement IRecordInfo interface for this to return.
func safeArrayGetRecordInfo(safearray *SafeArray) (recordInfo interface{}, err error) {
err = convertHresultToError(
procSafeArrayGetRecordInfo.Call(
uintptr(unsafe.Pointer(safearray)),
uintptr(unsafe.Pointer(&recordInfo))))
return
}
// safeArraySetRecordInfo mutates IRecordInfo info for custom types.
//
// AKA: SafeArraySetRecordInfo in Windows API.
//
// XXX: Must implement IRecordInfo interface for this to return.
func safeArraySetRecordInfo(safearray *SafeArray, recordInfo interface{}) (err error) {
err = convertHresultToError(
procSafeArraySetRecordInfo.Call(
uintptr(unsafe.Pointer(safearray)),
uintptr(unsafe.Pointer(&recordInfo))))
return
}

View File

@ -1,140 +0,0 @@
// Helper for converting SafeArray to array of objects.
package ole
import (
"unsafe"
)
type SafeArrayConversion struct {
Array *SafeArray
}
func (sac *SafeArrayConversion) ToStringArray() (strings []string) {
totalElements, _ := sac.TotalElements(0)
strings = make([]string, totalElements)
for i := int32(0); i < totalElements; i++ {
strings[int32(i)], _ = safeArrayGetElementString(sac.Array, i)
}
return
}
func (sac *SafeArrayConversion) ToByteArray() (bytes []byte) {
totalElements, _ := sac.TotalElements(0)
bytes = make([]byte, totalElements)
for i := int32(0); i < totalElements; i++ {
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&bytes[int32(i)]))
}
return
}
func (sac *SafeArrayConversion) ToValueArray() (values []interface{}) {
totalElements, _ := sac.TotalElements(0)
values = make([]interface{}, totalElements)
vt, _ := safeArrayGetVartype(sac.Array)
for i := int32(0); i < totalElements; i++ {
switch VT(vt) {
case VT_BOOL:
var v bool
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v
case VT_I1:
var v int8
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v
case VT_I2:
var v int16
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v
case VT_I4:
var v int32
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v
case VT_I8:
var v int64
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v
case VT_UI1:
var v uint8
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v
case VT_UI2:
var v uint16
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v
case VT_UI4:
var v uint32
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v
case VT_UI8:
var v uint64
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v
case VT_R4:
var v float32
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v
case VT_R8:
var v float64
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v
case VT_BSTR:
var v string
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v
case VT_VARIANT:
var v VARIANT
safeArrayGetElement(sac.Array, i, unsafe.Pointer(&v))
values[i] = v.Value()
default:
// TODO
}
}
return
}
func (sac *SafeArrayConversion) GetType() (varType uint16, err error) {
return safeArrayGetVartype(sac.Array)
}
func (sac *SafeArrayConversion) GetDimensions() (dimensions *uint32, err error) {
return safeArrayGetDim(sac.Array)
}
func (sac *SafeArrayConversion) GetSize() (length *uint32, err error) {
return safeArrayGetElementSize(sac.Array)
}
func (sac *SafeArrayConversion) TotalElements(index uint32) (totalElements int32, err error) {
if index < 1 {
index = 1
}
// Get array bounds
var LowerBounds int32
var UpperBounds int32
LowerBounds, err = safeArrayGetLBound(sac.Array, index)
if err != nil {
return
}
UpperBounds, err = safeArrayGetUBound(sac.Array, index)
if err != nil {
return
}
totalElements = UpperBounds - LowerBounds + 1
return
}
// Release Safe Array memory
func (sac *SafeArrayConversion) Release() {
safeArrayDestroy(sac.Array)
}

View File

@ -1,33 +0,0 @@
// +build windows
package ole
import (
"unsafe"
)
func safeArrayFromByteSlice(slice []byte) *SafeArray {
array, _ := safeArrayCreateVector(VT_UI1, 0, uint32(len(slice)))
if array == nil {
panic("Could not convert []byte to SAFEARRAY")
}
for i, v := range slice {
safeArrayPutElement(array, int64(i), uintptr(unsafe.Pointer(&v)))
}
return array
}
func safeArrayFromStringSlice(slice []string) *SafeArray {
array, _ := safeArrayCreateVector(VT_BSTR, 0, uint32(len(slice)))
if array == nil {
panic("Could not convert []string to SAFEARRAY")
}
// SysAllocStringLen(s)
for i, v := range slice {
safeArrayPutElement(array, int64(i), uintptr(unsafe.Pointer(SysAllocStringLen(v))))
}
return array
}

View File

@ -1,101 +0,0 @@
package ole
import (
"unicode/utf16"
"unsafe"
)
// ClassIDFrom retrieves class ID whether given is program ID or application string.
//
// Helper that provides check against both Class ID from Program ID and Class ID from string. It is
// faster, if you know which you are using, to use the individual functions, but this will check
// against available functions for you.
func ClassIDFrom(programID string) (classID *GUID, err error) {
classID, err = CLSIDFromProgID(programID)
if err != nil {
classID, err = CLSIDFromString(programID)
if err != nil {
return
}
}
return
}
// BytePtrToString converts byte pointer to a Go string.
func BytePtrToString(p *byte) string {
a := (*[10000]uint8)(unsafe.Pointer(p))
i := 0
for a[i] != 0 {
i++
}
return string(a[:i])
}
// UTF16PtrToString is alias for LpOleStrToString.
//
// Kept for compatibility reasons.
func UTF16PtrToString(p *uint16) string {
return LpOleStrToString(p)
}
// LpOleStrToString converts COM Unicode to Go string.
func LpOleStrToString(p *uint16) string {
if p == nil {
return ""
}
length := lpOleStrLen(p)
a := make([]uint16, length)
ptr := unsafe.Pointer(p)
for i := 0; i < int(length); i++ {
a[i] = *(*uint16)(ptr)
ptr = unsafe.Pointer(uintptr(ptr) + 2)
}
return string(utf16.Decode(a))
}
// BstrToString converts COM binary string to Go string.
func BstrToString(p *uint16) string {
if p == nil {
return ""
}
length := SysStringLen((*int16)(unsafe.Pointer(p)))
a := make([]uint16, length)
ptr := unsafe.Pointer(p)
for i := 0; i < int(length); i++ {
a[i] = *(*uint16)(ptr)
ptr = unsafe.Pointer(uintptr(ptr) + 2)
}
return string(utf16.Decode(a))
}
// lpOleStrLen returns the length of Unicode string.
func lpOleStrLen(p *uint16) (length int64) {
if p == nil {
return 0
}
ptr := unsafe.Pointer(p)
for i := 0; ; i++ {
if 0 == *(*uint16)(ptr) {
length = int64(i)
break
}
ptr = unsafe.Pointer(uintptr(ptr) + 2)
}
return
}
// convertHresultToError converts syscall to error, if call is unsuccessful.
func convertHresultToError(hr uintptr, r2 uintptr, ignore error) (err error) {
if hr != 0 {
err = NewError(hr)
}
return
}

View File

@ -1,15 +0,0 @@
// +build windows
package ole
import (
"golang.org/x/sys/windows"
)
var (
modcombase = windows.NewLazySystemDLL("combase.dll")
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
modole32 = windows.NewLazySystemDLL("ole32.dll")
modoleaut32 = windows.NewLazySystemDLL("oleaut32.dll")
moduser32 = windows.NewLazySystemDLL("user32.dll")
)

View File

@ -1,105 +0,0 @@
package ole
import "unsafe"
// NewVariant returns new variant based on type and value.
func NewVariant(vt VT, val int64) VARIANT {
return VARIANT{VT: vt, Val: val}
}
// ToIUnknown converts Variant to Unknown object.
func (v *VARIANT) ToIUnknown() *IUnknown {
if v.VT != VT_UNKNOWN {
return nil
}
return (*IUnknown)(unsafe.Pointer(uintptr(v.Val)))
}
// ToIDispatch converts variant to dispatch object.
func (v *VARIANT) ToIDispatch() *IDispatch {
if v.VT != VT_DISPATCH {
return nil
}
return (*IDispatch)(unsafe.Pointer(uintptr(v.Val)))
}
// ToArray converts variant to SafeArray helper.
func (v *VARIANT) ToArray() *SafeArrayConversion {
if v.VT != VT_SAFEARRAY {
if v.VT&VT_ARRAY == 0 {
return nil
}
}
var safeArray *SafeArray = (*SafeArray)(unsafe.Pointer(uintptr(v.Val)))
return &SafeArrayConversion{safeArray}
}
// ToString converts variant to Go string.
func (v *VARIANT) ToString() string {
if v.VT != VT_BSTR {
return ""
}
return BstrToString(*(**uint16)(unsafe.Pointer(&v.Val)))
}
// Clear the memory of variant object.
func (v *VARIANT) Clear() error {
return VariantClear(v)
}
// Value returns variant value based on its type.
//
// Currently supported types: 2- and 4-byte integers, strings, bools.
// Note that 64-bit integers, datetimes, and other types are stored as strings
// and will be returned as strings.
//
// Needs to be further converted, because this returns an interface{}.
func (v *VARIANT) Value() interface{} {
switch v.VT {
case VT_I1:
return int8(v.Val)
case VT_UI1:
return uint8(v.Val)
case VT_I2:
return int16(v.Val)
case VT_UI2:
return uint16(v.Val)
case VT_I4:
return int32(v.Val)
case VT_UI4:
return uint32(v.Val)
case VT_I8:
return int64(v.Val)
case VT_UI8:
return uint64(v.Val)
case VT_INT:
return int(v.Val)
case VT_UINT:
return uint(v.Val)
case VT_INT_PTR:
return uintptr(v.Val) // TODO
case VT_UINT_PTR:
return uintptr(v.Val)
case VT_R4:
return *(*float32)(unsafe.Pointer(&v.Val))
case VT_R8:
return *(*float64)(unsafe.Pointer(&v.Val))
case VT_BSTR:
return v.ToString()
case VT_DATE:
// VT_DATE type will either return float64 or time.Time.
d := uint64(v.Val)
date, err := GetVariantDate(d)
if err != nil {
return float64(v.Val)
}
return date
case VT_UNKNOWN:
return v.ToIUnknown()
case VT_DISPATCH:
return v.ToIDispatch()
case VT_BOOL:
return v.Val != 0
}
return nil
}

View File

@ -1,11 +0,0 @@
// +build 386
package ole
type VARIANT struct {
VT VT // 2
wReserved1 uint16 // 4
wReserved2 uint16 // 6
wReserved3 uint16 // 8
Val int64 // 16
}

View File

@ -1,12 +0,0 @@
// +build amd64
package ole
type VARIANT struct {
VT VT // 2
wReserved1 uint16 // 4
wReserved2 uint16 // 6
wReserved3 uint16 // 8
Val int64 // 16
_ [8]byte // 24
}

View File

@ -1,22 +0,0 @@
// +build windows,386
package ole
import (
"errors"
"syscall"
"time"
"unsafe"
)
// GetVariantDate converts COM Variant Time value to Go time.Time.
func GetVariantDate(value uint64) (time.Time, error) {
var st syscall.Systemtime
v1 := uint32(value)
v2 := uint32(value >> 32)
r, _, _ := procVariantTimeToSystemTime.Call(uintptr(v1), uintptr(v2), uintptr(unsafe.Pointer(&st)))
if r != 0 {
return time.Date(int(st.Year), time.Month(st.Month), int(st.Day), int(st.Hour), int(st.Minute), int(st.Second), int(st.Milliseconds/1000), time.UTC), nil
}
return time.Now(), errors.New("Could not convert to time, passing current time.")
}

View File

@ -1,20 +0,0 @@
// +build windows,amd64
package ole
import (
"errors"
"syscall"
"time"
"unsafe"
)
// GetVariantDate converts COM Variant Time value to Go time.Time.
func GetVariantDate(value uint64) (time.Time, error) {
var st syscall.Systemtime
r, _, _ := procVariantTimeToSystemTime.Call(uintptr(value), uintptr(unsafe.Pointer(&st)))
if r != 0 {
return time.Date(int(st.Year), time.Month(st.Month), int(st.Day), int(st.Hour), int(st.Minute), int(st.Second), int(st.Milliseconds/1000), time.UTC), nil
}
return time.Now(), errors.New("Could not convert to time, passing current time.")
}

View File

@ -1,12 +0,0 @@
// +build ppc64le
package ole
type VARIANT struct {
VT VT // 2
wReserved1 uint16 // 4
wReserved2 uint16 // 6
wReserved3 uint16 // 8
Val int64 // 16
_ [8]byte // 24
}

View File

@ -1,12 +0,0 @@
// +build s390x
package ole
type VARIANT struct {
VT VT // 2
wReserved1 uint16 // 4
wReserved2 uint16 // 6
wReserved3 uint16 // 8
Val int64 // 16
_ [8]byte // 24
}

View File

@ -1,58 +0,0 @@
// generated by stringer -output vt_string.go -type VT; DO NOT EDIT
package ole
import "fmt"
const (
_VT_name_0 = "VT_EMPTYVT_NULLVT_I2VT_I4VT_R4VT_R8VT_CYVT_DATEVT_BSTRVT_DISPATCHVT_ERRORVT_BOOLVT_VARIANTVT_UNKNOWNVT_DECIMAL"
_VT_name_1 = "VT_I1VT_UI1VT_UI2VT_UI4VT_I8VT_UI8VT_INTVT_UINTVT_VOIDVT_HRESULTVT_PTRVT_SAFEARRAYVT_CARRAYVT_USERDEFINEDVT_LPSTRVT_LPWSTR"
_VT_name_2 = "VT_RECORDVT_INT_PTRVT_UINT_PTR"
_VT_name_3 = "VT_FILETIMEVT_BLOBVT_STREAMVT_STORAGEVT_STREAMED_OBJECTVT_STORED_OBJECTVT_BLOB_OBJECTVT_CFVT_CLSID"
_VT_name_4 = "VT_BSTR_BLOBVT_VECTOR"
_VT_name_5 = "VT_ARRAY"
_VT_name_6 = "VT_BYREF"
_VT_name_7 = "VT_RESERVED"
_VT_name_8 = "VT_ILLEGAL"
)
var (
_VT_index_0 = [...]uint8{0, 8, 15, 20, 25, 30, 35, 40, 47, 54, 65, 73, 80, 90, 100, 110}
_VT_index_1 = [...]uint8{0, 5, 11, 17, 23, 28, 34, 40, 47, 54, 64, 70, 82, 91, 105, 113, 122}
_VT_index_2 = [...]uint8{0, 9, 19, 30}
_VT_index_3 = [...]uint8{0, 11, 18, 27, 37, 55, 71, 85, 90, 98}
_VT_index_4 = [...]uint8{0, 12, 21}
_VT_index_5 = [...]uint8{0, 8}
_VT_index_6 = [...]uint8{0, 8}
_VT_index_7 = [...]uint8{0, 11}
_VT_index_8 = [...]uint8{0, 10}
)
func (i VT) String() string {
switch {
case 0 <= i && i <= 14:
return _VT_name_0[_VT_index_0[i]:_VT_index_0[i+1]]
case 16 <= i && i <= 31:
i -= 16
return _VT_name_1[_VT_index_1[i]:_VT_index_1[i+1]]
case 36 <= i && i <= 38:
i -= 36
return _VT_name_2[_VT_index_2[i]:_VT_index_2[i+1]]
case 64 <= i && i <= 72:
i -= 64
return _VT_name_3[_VT_index_3[i]:_VT_index_3[i+1]]
case 4095 <= i && i <= 4096:
i -= 4095
return _VT_name_4[_VT_index_4[i]:_VT_index_4[i+1]]
case i == 8192:
return _VT_name_5
case i == 16384:
return _VT_name_6
case i == 32768:
return _VT_name_7
case i == 65535:
return _VT_name_8
default:
return fmt.Sprintf("VT(%d)", i)
}
}

Some files were not shown because too many files have changed in this diff Show More