diff --git a/codec.go b/codec.go index f034a41..9fef2da 100644 --- a/codec.go +++ b/codec.go @@ -2,6 +2,7 @@ package multiaddr import ( "encoding/binary" + "errors" "fmt" "net" "strconv" @@ -55,7 +56,14 @@ func bytesToString(b []byte) (ret string, err error) { defer func() { if e := recover(); e != nil { ret = "" - err = e.(error) + switch e := e.(type) { + case error: + err = e + case string: + err = errors.New(e) + default: + err = fmt.Errorf("%v", e) + } } }() @@ -69,25 +77,38 @@ func bytesToString(b []byte) (ret string, err error) { if p.Code == 0 { return "", fmt.Errorf("no protocol with code %d", code) } - s = strings.Join([]string{s, "/", p.Name}, "") + s += "/" + p.Name if p.Size == 0 { continue } - a, err := addressBytesToString(p, b[:(p.Size/8)]) + size := sizeForAddr(p, b) + a, err := addressBytesToString(p, b[:size]) if err != nil { return "", err } if len(a) > 0 { - s = strings.Join([]string{s, "/", a}, "") + s += "/" + a } - b = b[(p.Size / 8):] + b = b[size:] } return s, nil } +func sizeForAddr(p Protocol, b []byte) int { + switch { + case p.Size > 0: + return (p.Size / 8) + case p.Size == 0: + return 0 + default: + size, n := ReadVarintCode(b) + return size + n + } +} + func bytesSplit(b []byte) (ret [][]byte, err error) { // panic handler, in case we try accessing bytes incorrectly. defer func() { @@ -105,7 +126,8 @@ func bytesSplit(b []byte) (ret [][]byte, err error) { return [][]byte{}, fmt.Errorf("no protocol with code %d", b[0]) } - length := n + (p.Size / 8) + size := sizeForAddr(p, b[n:]) + length := n + size ret = append(ret, b[:length]) b = b[length:] } @@ -144,12 +166,14 @@ func addressStringToBytes(p Protocol, s string) ([]byte, error) { return b, nil case P_IPFS: // ipfs - // the address is a multihash string representation + // the address is a varint prefixed multihash string representation m, err := mh.FromB58String(s) if err != nil { return nil, fmt.Errorf("failed to parse ipfs addr: %s %s", s, err) } - return []byte(m), nil + size := CodeToVarint(len(m)) + b := append(size, m...) + return b, nil } return []byte{}, fmt.Errorf("failed to parse %s addr: unknown", p.Name) @@ -168,7 +192,12 @@ func addressBytesToString(p Protocol, b []byte) (string, error) { return strconv.Itoa(int(i)), nil case P_IPFS: // ipfs - // the address is a multihash string representation + // the address is a varint-prefixed multihash string representation + size, n := ReadVarintCode(b) + b = b[n:] + if len(b) != size { + panic("inconsistent lengths") + } m, err := mh.Cast(b) if err != nil { return "", err diff --git a/multiaddr.go b/multiaddr.go index 373c2c1..1cb7ad4 100644 --- a/multiaddr.go +++ b/multiaddr.go @@ -64,6 +64,7 @@ func (m *multiaddr) Protocols() []Protocol { } }() + size := 0 ps := []Protocol{} b := m.bytes[:] for len(b) > 0 { @@ -75,7 +76,10 @@ func (m *multiaddr) Protocols() []Protocol { panic(fmt.Errorf("no protocol with code %d", b[0])) } ps = append(ps, p) - b = b[n+(p.Size/8):] + b = b[n:] + + size = sizeForAddr(p, b) + b = b[size:] } return ps }