codec.go 3.33 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2
package multiaddr

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
3
import (
4
	"bytes"
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
5 6
	"fmt"
	"strings"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
7 8
)

9
func stringToBytes(s string) ([]byte, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
10 11 12 13

	// consume trailing slashes
	s = strings.TrimRight(s, "/")

14
	var b bytes.Buffer
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
15
	sp := strings.Split(s, "/")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
16

17 18 19 20
	if sp[0] != "" {
		return nil, fmt.Errorf("invalid multiaddr, must begin with /")
	}

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
21 22
	// consume first empty elem
	sp = sp[1:]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
23

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
24 25
	for len(sp) > 0 {
		p := ProtocolWithName(sp[0])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
26
		if p.Code == 0 {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
27 28
			return nil, fmt.Errorf("no protocol with name %s", sp[0])
		}
29
		_, _ = b.Write(CodeToVarint(p.Code))
30
		sp = sp[1:]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
31

32 33 34 35 36 37 38
		if p.Size == 0 { // no length.
			continue
		}

		if len(sp) < 1 {
			return nil, fmt.Errorf("protocol requires address, none given: %s", p.Name)
		}
39

jbenet's avatar
jbenet committed
40 41 42 43 44 45
		if p.Path {
			// it's a path protocol (terminal).
			// consume the rest of the address as the next component.
			sp = []string{"/" + strings.Join(sp, "/")}
		}

46
		a, err := p.Transcoder.StringToBytes(sp[0])
47 48
		if err != nil {
			return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
49
		}
50
		if p.Size < 0 { // varint size.
51
			_, _ = b.Write(CodeToVarint(len(a)))
52
		}
53
		b.Write(a)
54
		sp = sp[1:]
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
55
	}
56 57

	return b.Bytes(), nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
58 59
}

60 61 62
func validateBytes(b []byte) (err error) {
	for len(b) > 0 {
		code, n, err := ReadVarintCode(b)
Jeromy's avatar
Jeromy committed
63 64 65 66
		if err != nil {
			return err
		}

67 68 69 70 71 72 73 74 75
		b = b[n:]
		p := ProtocolWithCode(code)
		if p.Code == 0 {
			return fmt.Errorf("no protocol with code %d", code)
		}

		if p.Size == 0 {
			continue
		}
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
76

77
		n, size, err := sizeForAddr(p, b)
78 79 80 81
		if err != nil {
			return err
		}

82 83
		b = b[n:]

Jeromy's avatar
Jeromy committed
84
		if len(b) < size || size < 0 {
85 86
			return fmt.Errorf("invalid value for size")
		}
Jeromy's avatar
Jeromy committed
87

88 89 90 91 92
		err = p.Transcoder.ValidateBytes(b[:size])
		if err != nil {
			return err
		}

93 94 95 96 97
		b = b[size:]
	}

	return nil
}
Jeromy's avatar
Jeromy committed
98

Steven Allen's avatar
Steven Allen committed
99 100 101 102 103 104 105
func readComponent(b []byte) (int, Component, error) {
	var offset int
	code, n, err := ReadVarintCode(b)
	if err != nil {
		return 0, Component{}, err
	}
	offset += n
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
106

Steven Allen's avatar
Steven Allen committed
107 108 109 110
	p := ProtocolWithCode(code)
	if p.Code == 0 {
		return 0, Component{}, fmt.Errorf("no protocol with code %d", code)
	}
111

Steven Allen's avatar
Steven Allen committed
112 113 114 115 116 117 118
	if p.Size == 0 {
		return offset, Component{
			bytes:    b[:offset],
			offset:   offset,
			protocol: p,
		}, nil
	}
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
119

Steven Allen's avatar
Steven Allen committed
120 121 122 123
	n, size, err := sizeForAddr(p, b[offset:])
	if err != nil {
		return 0, Component{}, err
	}
124

Steven Allen's avatar
Steven Allen committed
125
	offset += n
126

Steven Allen's avatar
Steven Allen committed
127 128 129
	if len(b[offset:]) < size || size < 0 {
		return 0, Component{}, fmt.Errorf("invalid value for size")
	}
130

Steven Allen's avatar
Steven Allen committed
131 132 133 134 135 136
	return offset + size, Component{
		bytes:    b[:offset+size],
		protocol: p,
		offset:   offset,
	}, nil
}
137

Steven Allen's avatar
Steven Allen committed
138 139 140 141 142
func bytesToString(b []byte) (ret string, err error) {
	var buf strings.Builder

	for len(b) > 0 {
		n, c, err := readComponent(b)
143 144 145
		if err != nil {
			return "", err
		}
Steven Allen's avatar
Steven Allen committed
146 147
		b = b[n:]
		c.writeTo(&buf)
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
148 149
	}

Steven Allen's avatar
Steven Allen committed
150
	return buf.String(), nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
151
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
152

153
func sizeForAddr(p Protocol, b []byte) (skip, size int, err error) {
154 155
	switch {
	case p.Size > 0:
156
		return 0, (p.Size / 8), nil
157
	case p.Size == 0:
158
		return 0, 0, nil
159
	default:
160 161
		size, n, err := ReadVarintCode(b)
		if err != nil {
162
			return 0, 0, err
163
		}
164
		return n, size, nil
165 166 167
	}
}

168 169 170 171 172 173
func bytesSplit(b []byte) ([][]byte, error) {
	var ret [][]byte
	for len(b) > 0 {
		code, n, err := ReadVarintCode(b)
		if err != nil {
			return nil, err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
174 175
		}

176
		p := ProtocolWithCode(code)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
177
		if p.Code == 0 {
178 179 180
			return nil, fmt.Errorf("no protocol with code %d", b[0])
		}

181
		n2, size, err := sizeForAddr(p, b[n:])
182 183
		if err != nil {
			return nil, err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
184 185
		}

186
		length := n + n2 + size
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
187 188 189 190 191 192
		ret = append(ret, b[:length])
		b = b[length:]
	}

	return ret, nil
}