Compare commits

...

24 Commits

Author SHA1 Message Date
Joel Wetzell 7a5ef4c56b Merge pull request #27 from jwetzell/dependabot/github_actions/actions/checkout-7
Bump actions/checkout from 6 to 7
2026-07-13 13:27:51 -05:00
Joel Wetzell 113cb622e8 Merge pull request #28 from jwetzell/dependabot/go_modules/github.com/urfave/cli/v3-3.10.1
Bump github.com/urfave/cli/v3 from 3.9.0 to 3.10.1
2026-07-13 13:25:51 -05:00
dependabot[bot] 1994949841 Bump github.com/urfave/cli/v3 from 3.9.0 to 3.10.1
Bumps [github.com/urfave/cli/v3](https://github.com/urfave/cli) from 3.9.0 to 3.10.1.
- [Release notes](https://github.com/urfave/cli/releases)
- [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md)
- [Commits](https://github.com/urfave/cli/compare/v3.9.0...v3.10.1)

---
updated-dependencies:
- dependency-name: github.com/urfave/cli/v3
  dependency-version: 3.10.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-29 02:53:22 +00:00
dependabot[bot] fe499f0c21 Bump actions/checkout from 6 to 7
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-22 02:53:16 +00:00
Joel Wetzell 2278ad7a1c Merge pull request #25 from jwetzell/dependabot/github_actions/codecov/codecov-action-7
Bump codecov/codecov-action from 6 to 7
2026-06-10 11:37:11 -05:00
Joel Wetzell d4a56fcd11 rename variables 2026-06-08 12:23:40 -05:00
dependabot[bot] e8626ab230 Bump codecov/codecov-action from 6 to 7
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 6 to 7.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-08 02:53:29 +00:00
Joel Wetzell 58672c9ab3 mess around with benchmarks and fuzzing 2026-05-20 17:41:57 -05:00
Joel Wetzell 8b8129b2e2 add size check to bundle content 2026-05-20 17:41:37 -05:00
Joel Wetzell f7850ce70e Merge pull request #24 from jwetzell/fix/float-64-arg-size-check
fix size check on readOSCFloat64
2026-05-20 17:39:59 -05:00
Joel Wetzell 8ed1ab065c fix size check on readOSCFloat64 2026-05-20 08:38:26 -05:00
Joel Wetzell 82e9c7ed24 Merge pull request #23 from jwetzell/dependabot/go_modules/github.com/urfave/cli/v3-3.9.0
Bump github.com/urfave/cli/v3 from 3.8.0 to 3.9.0
2026-05-19 14:34:06 -05:00
dependabot[bot] 9f34a57141 Bump github.com/urfave/cli/v3 from 3.8.0 to 3.9.0
Bumps [github.com/urfave/cli/v3](https://github.com/urfave/cli) from 3.8.0 to 3.9.0.
- [Release notes](https://github.com/urfave/cli/releases)
- [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md)
- [Commits](https://github.com/urfave/cli/compare/v3.8.0...v3.9.0)

---
updated-dependencies:
- dependency-name: github.com/urfave/cli/v3
  dependency-version: 3.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 03:23:16 +00:00
Joel Wetzell 6aadaedb5d some linting things 2026-05-17 09:22:14 -05:00
Joel Wetzell d6d4ac4419 stop using destination 2026-05-09 14:06:33 -05:00
Joel Wetzell a86a9b3121 chore: go fix 2026-05-09 13:44:28 -05:00
Joel Wetzell 216f84a2d9 Merge pull request #22 from jwetzell/error-handling-cleanup
clean out error return from funcs that don't return error
2026-04-29 13:56:47 -05:00
Joel Wetzell bd6a548e34 Add Codecov badge to README 2026-04-29 13:56:32 -05:00
Joel Wetzell d8dff0794a clean out error return from funcs that don't return error
Co-authored-by: Copilot <copilot@github.com>
2026-04-29 13:46:43 -05:00
Joel Wetzell 0c4d36b376 cleanup printing 2026-04-29 13:41:50 -05:00
Joel Wetzell a5ac419e3e return on unsupported arg 2026-04-29 13:41:42 -05:00
Joel Wetzell 3b66c38d18 Merge pull request #21 from jwetzell/dependabot/github_actions/codecov/codecov-action-6
Bump codecov/codecov-action from 5 to 6
2026-04-27 08:35:42 -05:00
Joel Wetzell 4d8ba2a47b get rid of bytes.Buffer use
Co-authored-by: Copilot <copilot@github.com>
2026-04-26 13:37:48 -05:00
dependabot[bot] 0caf1b02a7 Bump codecov/codecov-action from 5 to 6
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5 to 6.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-20 02:55:47 +00:00
18 changed files with 252 additions and 243 deletions
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
- goarch: "386"
goos: darwin
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: wangyoucao577/go-release-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
- goarch: "386"
goos: darwin
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: wangyoucao577/go-release-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
- goarch: "386"
goos: darwin
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: wangyoucao577/go-release-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
+2 -2
View File
@@ -9,7 +9,7 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Set up Go
uses: actions/setup-go@v6
with:
@@ -18,7 +18,7 @@ jobs:
run: go test -v -coverprofile=coverage.txt .
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v7
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: coverage.txt
+2
View File
@@ -1,3 +1,5 @@
[![codecov](https://codecov.io/gh/jwetzell/osc-go/branch/main/graph/badge.svg?token=DW3CCZELGI)](https://codecov.io/gh/jwetzell/osc-go)
A mostly complete OSC implementation and collection of command line OSC utilities written in Go. Mainly an exercise in learning Go.
## Utilities
+10 -11
View File
@@ -8,10 +8,7 @@ func (b *OSCBundle) ToBytes() ([]byte, error) {
bytes := stringToOSCBytes("#bundle")
timeTagBytes, err := timeTagToOSCBytes(b.TimeTag)
if err != nil {
return nil, err
}
timeTagBytes := timeTagToOSCBytes(b.TimeTag)
bytes = append(bytes, timeTagBytes...)
for _, packet := range b.Contents {
@@ -21,10 +18,7 @@ func (b *OSCBundle) ToBytes() ([]byte, error) {
}
packetLength := len(packetBytes)
packetLengthBytes, err := int32ToOSCBytes(int32(packetLength))
if err != nil {
return nil, err
}
packetLengthBytes := int32ToOSCBytes(int32(packetLength))
bytes = append(bytes, packetLengthBytes...)
bytes = append(bytes, packetBytes...)
}
@@ -72,25 +66,30 @@ func BundleFromBytes(bytes []byte) (*OSCBundle, []byte, error) {
remainingBytes = bytesAfterContentSize
if contentSize <= 0 {
return nil, remainingBytes, errors.New("bundle content size must be positive")
}
if len(remainingBytes) < int(contentSize) {
return nil, remainingBytes, errors.New("bundle doesn't have enough bytes for the content size it specifies")
}
bundleContentBytes := remainingBytes[0:contentSize]
if bundleContentBytes[0] == 35 {
switch bundleContentBytes[0] {
case 35: // #
content, _, err := BundleFromBytes(bundleContentBytes)
if err != nil {
return nil, remainingBytes, err
}
bundleContents = append(bundleContents, content)
} else if bundleContentBytes[0] == 47 {
case 47: // /
content, err := MessageFromBytes(bundleContentBytes)
if err != nil {
return nil, remainingBytes, err
}
bundleContents = append(bundleContents, content)
} else {
default:
return nil, remainingBytes, errors.New("bundle contents does not look a bundle or message")
}
remainingBytes = bytesAfterContentSize[contentSize:]
+28
View File
@@ -210,3 +210,31 @@ func TestBadOSCBundleDecoding(t *testing.T) {
})
}
}
func FuzzBundleFromBytes(f *testing.F) {
seedBytes := [][]byte{
{},
{35, 98, 117, 110, 100, 108, 101, 0, 0, 0, 0,
32, 0, 0, 0, 0, 0, 0, 0, 32, 47, 111,
115, 99, 105, 108, 108, 97, 116, 111, 114, 47, 52,
47, 102, 114, 101, 113, 117, 101, 110, 99, 121, 0,
44, 102, 0, 0, 67, 220, 0, 0},
{35, 98, 117, 110, 100, 108, 101, 0, // #bundle
0, 0, 0, 32, 0, 0, 0, 0, // time tag
0, 0, 0, 52, // content size
35, 98, 117, 110, 100, 108, 101, 0, // #bundle
0, 0, 0, 64, 0, 0, 0, 0, // time tag
0, 0, 0, 32, // content size
47, 111, 115, 99, 105, 108, 108, 97, 116, 111, 114, 47, 52,
47, 102, 114, 101, 113, 117, 101, 110, 99, 121, 0,
44, 102, 0, 0, 67, 220, 0, 0},
}
for _, seed := range seedBytes {
f.Add(seed)
}
f.Fuzz(func(t *testing.T, data []byte) {
_, _, _ = BundleFromBytes(data)
})
}
+22 -29
View File
@@ -12,41 +12,37 @@ import (
)
func main() {
var Address string
var Args []string
var Types []string
var Slip bool
cmd := &cli.Command{
Name: "makeosc",
Usage: "make osc bytes",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "address",
Value: "",
Usage: "OSC address",
Destination: &Address,
Required: true,
Name: "address",
Value: "",
Usage: "OSC address",
Required: true,
},
&cli.StringSliceFlag{
Name: "arg",
Usage: "OSC args",
Destination: &Args,
Name: "arg",
Usage: "OSC args",
},
&cli.StringSliceFlag{
Name: "type",
Usage: "OSC types",
Destination: &Types,
Name: "type",
Usage: "OSC types",
},
&cli.BoolFlag{
Name: "slip",
Value: false,
Usage: "whether to slip encode the OSC Message bytes",
Destination: &Slip,
Name: "slip",
Value: false,
Usage: "whether to slip encode the OSC Message bytes",
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
make(Address, Args, Types, Slip)
address := cmd.String("address")
args := cmd.StringSlice("arg")
types := cmd.StringSlice("type")
slip := cmd.Bool("slip")
makeMsg(address, args, types, slip)
return nil
},
}
@@ -130,8 +126,7 @@ func argToTypedArg(rawArg string, oscType string) osc.OSCArg {
Type: "N",
}
default:
fmt.Print("unhandled osc type: ")
fmt.Printf("%s.\n", oscType)
fmt.Printf("unsupported OSC arg type: %s\n", oscType)
// TODO(jwetzell): something better than this like actual nil, err thing
return osc.OSCArg{}
}
@@ -146,11 +141,12 @@ func slipEncode(bytes []byte) []byte {
var encodedBytes = []byte{END}
for _, byteToEncode := range bytes {
if byteToEncode == END {
switch byteToEncode {
case END:
encodedBytes = append(encodedBytes, ESC, ESC_END)
} else if byteToEncode == ESC {
case ESC:
encodedBytes = append(encodedBytes, ESC, ESC_ESC)
} else {
default:
encodedBytes = append(encodedBytes, byteToEncode)
}
}
@@ -159,7 +155,7 @@ func slipEncode(bytes []byte) []byte {
return encodedBytes
}
func make(address string, args []string, types []string, slip bool) {
func makeMsg(address string, args []string, types []string, slip bool) {
oscMessage := osc.OSCMessage{
Address: address,
@@ -183,8 +179,5 @@ func make(address string, args []string, types []string, slip bool) {
if slip {
oscMessageBuffer = slipEncode(oscMessageBuffer)
}
//TODO write buffer to stdout
os.Stdout.Write(oscMessageBuffer)
}
+33 -36
View File
@@ -12,33 +12,25 @@ import (
)
func main() {
var IP string
var Port int32
var Protocol string
var Format string
var Slip bool
cmd := &cli.Command{
Name: "receiveosc",
Usage: "receive OSC messages via UDP or TCP",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "ip",
Usage: "ip to receive OSC messages on",
Value: "0.0.0.0",
Destination: &IP,
Name: "ip",
Usage: "ip to receive OSC messages on",
Value: "0.0.0.0",
},
&cli.Int32Flag{
Name: "port",
Usage: "port to receive OSC messages on",
Destination: &Port,
Value: 8888,
Name: "port",
Usage: "port to receive OSC messages on",
Value: 8888,
},
&cli.StringFlag{
Name: "protocol",
Usage: "protocol to use to receive (tcp or udp)",
Value: "udp",
Destination: &Protocol,
Name: "protocol",
Usage: "protocol to use to receive (tcp or udp)",
Value: "udp",
Validator: func(flag string) error {
if flag != "udp" && flag != "tcp" {
return fmt.Errorf("protocol must be either 'udp' or 'tcp'")
@@ -47,10 +39,9 @@ func main() {
},
},
&cli.StringFlag{
Name: "format",
Usage: "format for messages to be output in ('json')",
Value: "json",
Destination: &Format,
Name: "format",
Usage: "format for messages to be output in ('json')",
Value: "json",
Validator: func(flag string) error {
if flag != "json" {
return fmt.Errorf("format must be 'json'")
@@ -59,22 +50,27 @@ func main() {
},
},
&cli.BoolFlag{
Name: "slip",
Value: false,
Usage: "whether to slip encode the OSC Message bytes",
Destination: &Slip,
Name: "slip",
Value: false,
Usage: "whether to slip encode the OSC Message bytes",
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
netAddress := fmt.Sprintf("%s:%d", IP, Port)
switch Protocol {
ip := cmd.String("ip")
port := cmd.Int32("port")
protocol := cmd.String("protocol")
format := cmd.String("format")
slip := cmd.Bool("slip")
netAddress := fmt.Sprintf("%s:%d", ip, port)
switch protocol {
case "udp":
listenUDP(netAddress, Format)
listenUDP(netAddress, format)
case "tcp":
if !Slip {
if !slip {
return fmt.Errorf("OSC 1.0 over TCP is not supported yet")
}
listenTCP(netAddress, Slip, Format)
listenTCP(netAddress, slip, format)
}
return nil
},
@@ -124,9 +120,10 @@ func (s *SLIP) decode(bytes []byte) {
}
if escapeNext {
if packetByte == ESC_END {
switch packetByte {
case ESC_END:
s.pendingBytes = append(s.pendingBytes, END)
} else if packetByte == ESC_ESC {
case ESC_ESC:
s.pendingBytes = append(s.pendingBytes, ESC)
}
escapeNext = false
@@ -207,23 +204,23 @@ func handleBundle(bundle *osc.OSCBundle, format string) {
func listenUDP(netAddress string, format string) {
s, err := net.ResolveUDPAddr("udp4", netAddress)
laddr, err := net.ResolveUDPAddr("udp4", netAddress)
if err != nil {
fmt.Println(err)
return
}
connection, err := net.ListenUDP("udp4", s)
conn, err := net.ListenUDP("udp4", laddr)
if err != nil {
fmt.Println(err)
return
}
defer connection.Close()
defer conn.Close()
buffer := make([]byte, 1024)
for {
bytesRead, _, err := connection.ReadFromUDP(buffer)
bytesRead, _, err := conn.ReadFromUDP(buffer)
if err != nil {
panic(err)
+35 -42
View File
@@ -15,35 +15,25 @@ import (
)
func main() {
var Host string
var Port int32
var Address string
var Protocol string
var Args []string
var Types []string
var Slip bool
cmd := &cli.Command{
Name: "sendosc",
Usage: "send OSC messages via UDP or TCP",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "host",
Usage: "host to send OSC message to",
Destination: &Host,
Required: true,
Name: "host",
Usage: "host to send OSC message to",
Required: true,
},
&cli.Int32Flag{
Name: "port",
Usage: "port to send OSC message to",
Destination: &Port,
Required: true,
Name: "port",
Usage: "port to send OSC message to",
Required: true,
},
&cli.StringFlag{
Name: "protocol",
Usage: "protocol to use to send (tcp or udp)",
Value: "udp",
Destination: &Protocol,
Name: "protocol",
Usage: "protocol to use to send (tcp or udp)",
Value: "udp",
Validator: func(flag string) error {
if flag != "udp" && flag != "tcp" {
return fmt.Errorf("protocol must be either 'udp' or 'tcp'")
@@ -52,32 +42,35 @@ func main() {
},
},
&cli.StringFlag{
Name: "address",
Usage: "OSC address",
Destination: &Address,
Required: true,
Name: "address",
Usage: "OSC address",
Required: true,
},
&cli.StringSliceFlag{
Name: "arg",
Usage: "OSC args",
Value: []string{},
Destination: &Args,
Name: "arg",
Usage: "OSC args",
Value: []string{},
},
&cli.StringSliceFlag{
Name: "type",
Usage: "OSC types",
Value: []string{},
Destination: &Types,
Name: "type",
Usage: "OSC types",
Value: []string{},
},
&cli.BoolFlag{
Name: "slip",
Value: false,
Usage: "whether to slip encode the OSC Message bytes",
Destination: &Slip,
Name: "slip",
Value: false,
Usage: "whether to slip encode the OSC Message bytes",
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
send(Host, Port, Address, Args, Types, Protocol, Slip)
host := cmd.String("host")
port := cmd.Int32("port")
address := cmd.String("address")
args := cmd.StringSlice("arg")
types := cmd.StringSlice("type")
protocol := cmd.String("protocol")
slip := cmd.Bool("slip")
send(host, port, address, args, types, protocol, slip)
return nil
},
}
@@ -161,8 +154,7 @@ func argToTypedArg(rawArg string, oscType string) osc.OSCArg {
Type: "N",
}
default:
fmt.Print("unhandled osc type: ")
fmt.Printf("%s.\n", oscType)
fmt.Printf("unsupported OSC arg type: %s\n", oscType)
// TODO(jwetzell): something better than this like actual nil, err thing
return osc.OSCArg{}
}
@@ -177,11 +169,12 @@ func slipEncode(bytes []byte) []byte {
var encodedBytes = []byte{END}
for _, byteToEncode := range bytes {
if byteToEncode == END {
switch byteToEncode {
case END:
encodedBytes = append(encodedBytes, ESC, ESC_END)
} else if byteToEncode == ESC {
case ESC:
encodedBytes = append(encodedBytes, ESC, ESC_ESC)
} else {
default:
encodedBytes = append(encodedBytes, byteToEncode)
}
}
@@ -223,7 +216,7 @@ func send(host string, port int32, address string, args []string, types []string
oscMessageBuffer = append(sizeBytes, oscMessageBuffer...)
}
netAddress := fmt.Sprintf("%s:%d", host, port)
netAddress := net.JoinHostPort(host, fmt.Sprintf("%d", port))
conn, err := net.Dial(protocol, netAddress)
if err != nil {
fmt.Printf("Dial err %v", err)
+1 -1
View File
@@ -2,4 +2,4 @@ module github.com/jwetzell/osc-go
go 1.25.1
require github.com/urfave/cli/v3 v3.8.0
require github.com/urfave/cli/v3 v3.10.1
+2 -2
View File
@@ -4,7 +4,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/urfave/cli/v3 v3.8.0 h1:XqKPrm0q4P0q5JpoclYoCAv0/MIvH/jZ2umzuf8pNTI=
github.com/urfave/cli/v3 v3.8.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
github.com/urfave/cli/v3 v3.10.1 h1:7Kx9H50hrHbRbyxgO1KP6/BcbiGRz0uYh5YyQ30JEEY=
github.com/urfave/cli/v3 v3.10.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+43
View File
@@ -511,3 +511,46 @@ func TestBadOSCMessageDecoding(t *testing.T) {
})
}
}
func BenchmarkMessageToBytes(b *testing.B) {
message := &OSCMessage{
Address: "/hello",
Args: []OSCArg{
{Type: "i", Value: 35},
},
}
for b.Loop() {
_, err := message.ToBytes()
if err != nil {
b.Fatalf("failed to encode properly: %s", err.Error())
}
}
}
func BenchmarkMessageFromBytes(b *testing.B) {
bytes := []byte{47, 104, 101, 108, 108, 111, 0, 0, 44, 105, 0, 0, 0, 0, 0, 35}
for b.Loop() {
_, err := MessageFromBytes(bytes)
if err != nil {
b.Fatalf("failed to decode properly: %s", err.Error())
}
}
}
func FuzzMessageFromBytes(f *testing.F) {
seedBytes := [][]byte{
{},
{47, 104, 101, 108, 108, 111, 0, 0},
{47, 104, 101, 108, 108, 111, 0, 0, 44, 105, 0, 0, 0, 0, 0, 35},
}
for _, seed := range seedBytes {
f.Add(seed)
}
f.Fuzz(func(t *testing.T, data []byte) {
_, _ = MessageFromBytes(data)
})
}
+63 -117
View File
@@ -2,7 +2,6 @@ package osc
// TODO(jwetzell): split things up
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
@@ -18,7 +17,7 @@ func stringToOSCBytes(rawString string) []byte {
padLength := 4 - (len(sb.String()) % 4)
if padLength < 4 {
for i := 0; i < padLength; i++ {
for range padLength {
sb.WriteString("\u0000")
}
}
@@ -26,75 +25,64 @@ func stringToOSCBytes(rawString string) []byte {
return []byte(sb.String())
}
func int32ToOSCBytes(number int32) ([]byte, error) {
var buf bytes.Buffer
err := binary.Write(&buf, binary.BigEndian, number)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
func int32ToOSCBytes(number int32) []byte {
bytes := make([]byte, 4)
bytes[0] = byte((number >> 24) & 0xFF)
bytes[1] = byte((number >> 16) & 0xFF)
bytes[2] = byte((number >> 8) & 0xFF)
bytes[3] = byte(number & 0xFF)
return bytes
}
func int64ToOSCBytes(number int64) ([]byte, error) {
var buf bytes.Buffer
err := binary.Write(&buf, binary.BigEndian, number)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
func int64ToOSCBytes(number int64) []byte {
bytes := make([]byte, 8)
bytes[0] = byte((number >> 56) & 0xFF)
bytes[1] = byte((number >> 48) & 0xFF)
bytes[2] = byte((number >> 40) & 0xFF)
bytes[3] = byte((number >> 32) & 0xFF)
bytes[4] = byte((number >> 24) & 0xFF)
bytes[5] = byte((number >> 16) & 0xFF)
bytes[6] = byte((number >> 8) & 0xFF)
bytes[7] = byte(number & 0xFF)
return bytes
}
func float32ToOSCBytes(number float32) ([]byte, error) {
var buf bytes.Buffer
err := binary.Write(&buf, binary.BigEndian, number)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
func float32ToOSCBytes(number float32) []byte {
bytes := make([]byte, 4)
binary.BigEndian.PutUint32(bytes, math.Float32bits(number))
return bytes
}
func float64ToOSCBytes(number float64) ([]byte, error) {
var buf bytes.Buffer
err := binary.Write(&buf, binary.BigEndian, number)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
func float64ToOSCBytes(number float64) []byte {
bytes := make([]byte, 8)
binary.BigEndian.PutUint64(bytes, math.Float64bits(number))
return bytes
}
func byteArrayToOSCBytes(bytes []byte) ([]byte, error) {
func byteArrayToOSCBytes(bytes []byte) []byte {
oscBytes := []byte{}
bytesSize := len(bytes)
bytesSizeBytes, err := int32ToOSCBytes(int32(bytesSize))
if err != nil {
return nil, err
}
bytesSizeBytes := int32ToOSCBytes(int32(bytesSize))
oscBytes = append(oscBytes, bytesSizeBytes...)
oscBytes = append(oscBytes, bytes...)
padLength := 4 - (bytesSize % 4)
if padLength < 4 {
for i := 0; i < padLength; i++ {
for range padLength {
oscBytes = append(oscBytes, 0)
}
}
return oscBytes, nil
return oscBytes
}
func timeTagToOSCBytes(timeTag OSCTimeTag) ([]byte, error) {
timeTagBytes, err := int32ToOSCBytes(timeTag.seconds)
if err != nil {
return nil, err
}
fractionalSecondsBytes, err := int32ToOSCBytes(timeTag.fractionalSeconds)
if err != nil {
return nil, err
}
func timeTagToOSCBytes(timeTag OSCTimeTag) []byte {
timeTagBytes := int32ToOSCBytes(timeTag.seconds)
fractionalSecondsBytes := int32ToOSCBytes(timeTag.fractionalSeconds)
timeTagBytes = append(timeTagBytes, fractionalSecondsBytes...)
return timeTagBytes, nil
return timeTagBytes
}
func argsToBuffer(args []OSCArg) ([]byte, error) {
@@ -102,7 +90,7 @@ func argsToBuffer(args []OSCArg) ([]byte, error) {
var argBuffers = []byte{}
for _, arg := range args {
switch oscType := arg.Type; oscType {
switch arg.Type {
case "s":
if value, ok := arg.Value.(string); ok {
argBuffers = append(argBuffers, stringToOSCBytes(value)...)
@@ -111,60 +99,36 @@ func argsToBuffer(args []OSCArg) ([]byte, error) {
}
case "i":
if value, ok := arg.Value.(int); ok {
valueBytes, err := int32ToOSCBytes(int32(value))
if err != nil {
return nil, err
}
valueBytes := int32ToOSCBytes(int32(value))
argBuffers = append(argBuffers, valueBytes...)
} else if value, ok := arg.Value.(int32); ok {
valueBytes, err := int32ToOSCBytes(int32(value))
if err != nil {
return nil, err
}
valueBytes := int32ToOSCBytes(int32(value))
argBuffers = append(argBuffers, valueBytes...)
} else {
return nil, errors.New("OSC arg had int32 type but non-number value")
}
case "f":
if value, ok := arg.Value.(float32); ok {
valueBytes, err := float32ToOSCBytes(value)
if err != nil {
return nil, err
}
valueBytes := float32ToOSCBytes(value)
argBuffers = append(argBuffers, valueBytes...)
} else if value, ok := arg.Value.(float64); ok {
valueBytes, err := float32ToOSCBytes(float32(value))
if err != nil {
return nil, err
}
valueBytes := float32ToOSCBytes(float32(value))
argBuffers = append(argBuffers, valueBytes...)
} else if value, ok := arg.Value.(int); ok {
valueBytes, err := float32ToOSCBytes(float32(value))
if err != nil {
return nil, err
}
valueBytes := float32ToOSCBytes(float32(value))
argBuffers = append(argBuffers, valueBytes...)
} else if value, ok := arg.Value.(int32); ok {
valueBytes, err := float32ToOSCBytes(float32(value))
if err != nil {
return nil, err
}
valueBytes := float32ToOSCBytes(float32(value))
argBuffers = append(argBuffers, valueBytes...)
} else if value, ok := arg.Value.(int64); ok {
valueBytes, err := float32ToOSCBytes(float32(value))
if err != nil {
return nil, err
}
valueBytes := float32ToOSCBytes(float32(value))
argBuffers = append(argBuffers, valueBytes...)
} else {
return nil, errors.New("OSC arg had float32 type but non-number value")
}
case "b":
if value, ok := arg.Value.([]byte); ok {
valueBytes, err := byteArrayToOSCBytes(value)
if err != nil {
return nil, err
}
valueBytes := byteArrayToOSCBytes(value)
argBuffers = append(argBuffers, valueBytes...)
} else {
return nil, errors.New("OSC arg had blob type but non-blob value")
@@ -188,62 +152,38 @@ func argsToBuffer(args []OSCArg) ([]byte, error) {
}
case "h":
if value, ok := arg.Value.(int); ok {
valueBytes, err := int64ToOSCBytes(int64(value))
if err != nil {
return nil, err
}
valueBytes := int64ToOSCBytes(int64(value))
argBuffers = append(argBuffers, valueBytes...)
} else if value, ok := arg.Value.(int32); ok {
valueBytes, err := int64ToOSCBytes(int64(value))
if err != nil {
return nil, err
}
valueBytes := int64ToOSCBytes(int64(value))
argBuffers = append(argBuffers, valueBytes...)
} else if value, ok := arg.Value.(int64); ok {
valueBytes, err := int64ToOSCBytes(value)
if err != nil {
return nil, err
}
valueBytes := int64ToOSCBytes(value)
argBuffers = append(argBuffers, valueBytes...)
} else {
return nil, errors.New("OSC arg had int64 type but non-number value")
}
case "d":
if value, ok := arg.Value.(float32); ok {
valueBytes, err := float64ToOSCBytes(float64(value))
if err != nil {
return nil, err
}
valueBytes := float64ToOSCBytes(float64(value))
argBuffers = append(argBuffers, valueBytes...)
} else if value, ok := arg.Value.(float64); ok {
valueBytes, err := float64ToOSCBytes(value)
if err != nil {
return nil, err
}
valueBytes := float64ToOSCBytes(value)
argBuffers = append(argBuffers, valueBytes...)
} else if value, ok := arg.Value.(int); ok {
valueBytes, err := float64ToOSCBytes(float64(value))
if err != nil {
return nil, err
}
valueBytes := float64ToOSCBytes(float64(value))
argBuffers = append(argBuffers, valueBytes...)
} else if value, ok := arg.Value.(int32); ok {
valueBytes, err := float64ToOSCBytes(float64(value))
if err != nil {
return nil, err
}
valueBytes := float64ToOSCBytes(float64(value))
argBuffers = append(argBuffers, valueBytes...)
} else if value, ok := arg.Value.(int64); ok {
valueBytes, err := float64ToOSCBytes(float64(value))
if err != nil {
return nil, err
}
valueBytes := float64ToOSCBytes(float64(value))
argBuffers = append(argBuffers, valueBytes...)
} else {
return nil, errors.New("OSC arg had float64 type but non-number value")
}
default:
return nil, fmt.Errorf("unsupported OSC argument type: %s", oscType)
return nil, fmt.Errorf("unsupported OSC argument type: %s", arg.Type)
}
}
return argBuffers, nil
@@ -307,7 +247,7 @@ func readOSCFloat32(bytes []byte) (float32, []byte, error) {
}
func readOSCFloat64(bytes []byte) (float64, []byte, error) {
if len(bytes) < 4 {
if len(bytes) < 8 {
return 0, bytes, errors.New("OSC float64 arg is not 8 bytes")
}
bits := binary.BigEndian.Uint64(bytes[0:8])
@@ -321,6 +261,10 @@ func readOSCBlob(bytes []byte) ([]byte, []byte, error) {
return []byte{}, bytes, errors.New("OSC blob arg size not valid: " + err.Error())
}
if blobLength < 0 {
return []byte{}, bytes, errors.New("OSC blob arg size not valid: size cannot be negative")
}
if len(remainingBytes) < int(blobLength) {
return []byte{}, bytes, errors.New("OSC blob arg size not valid: size specified is larger than remaining bytes")
}
@@ -331,6 +275,9 @@ func readOSCBlob(bytes []byte) ([]byte, []byte, error) {
if blobLengthPadding < 4 {
blobEnd = blobEnd + blobLengthPadding
}
if int(blobEnd) > len(bytes) {
return []byte{}, bytes, errors.New("OSC blob arg size not valid: size specified is larger than remaining bytes when accounting for padding")
}
return bytes[4 : 4+blobLength], bytes[blobEnd:], nil
}
@@ -371,7 +318,7 @@ func readOSCArg(bytes []byte, oscType string) (OSCArg, []byte, error) {
oscArg := OSCArg{}
oscArg.Type = oscType
remainingBytes := []byte{}
var remainingBytes []byte
//TODO(jwetzell): add error handling
switch oscType {
case "s":
@@ -443,8 +390,7 @@ func readOSCArg(bytes []byte, oscType string) (OSCArg, []byte, error) {
oscArg.Value = argTimeTag
remainingBytes = bytesLeft
default:
fmt.Printf("unsupported osc type: %s\n", oscType)
readArgError = errors.New("unsupported OSC argument type: " + oscType)
return OSCArg{}, bytes, fmt.Errorf("unsupported OSC argument type: %s", oscType)
}
return oscArg, remainingBytes, readArgError
}
+2
View File
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("#bundle\x0000000000\x00\x00\x00\x00")
+2
View File
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("/00\x00,b0\x00\xff000")
+2
View File
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("/00\x00,b0\x00\x00\x00\x00\x010")
+2
View File
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("/00\x00,d\x0000000")