Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

bencode.gno

12.71 Kb · 480 lines
  1// Package bencode implements bencoding, the serialization format BitTorrent
  2// uses for .torrent files and tracker responses, as a pure reusable package.
  3//
  4// Four types, and that is the whole format: integers (i42e), byte strings
  5// (5:hello), lists (l...e) and dictionaries (d...e). There is no float, no
  6// boolean and no null, which is most of why the format fits in one file.
  7//
  8// The reason to reach for it over JSON is that bencode is CANONICAL: one value
  9// has exactly one encoding. Dictionary keys are sorted bytewise, integers carry
 10// no leading zeros and no negative zero, and strings carry their length instead
 11// of an escape syntax. An infohash is the digest of a re-encoded sub-dictionary,
 12// so a decoder that accepts a sloppy encoding and re-emits a tidy one silently
 13// changes the identity of the thing it parsed.
 14//
 15// This decoder is therefore strict: it REJECTS non-canonical input rather than
 16// normalizing it, so for every input it accepts, Decode followed by Encode
 17// returns the original bytes unchanged.
 18//
 19// A live demo of this package is at
 20// [r/moul/x/daily/bencodedemo](/r/moul/x/daily/bencodedemo/v0).
 21package bencode
 22
 23import (
 24	"errors"
 25	"strconv"
 26	"strings"
 27)
 28
 29// Limits, so a decode stays bounded on chain.
 30const (
 31	// MaxLen is the longest input Decode will look at.
 32	MaxLen = 8192
 33	// MaxDepth is how deeply lists and dictionaries may nest.
 34	MaxDepth = 16
 35)
 36
 37// Kind is the type of a [Value]: one of the four bencode types.
 38type Kind int
 39
 40// The four bencode types, plus the zero value.
 41const (
 42	KindInvalid Kind = iota
 43	KindInt
 44	KindString
 45	KindList
 46	KindDict
 47)
 48
 49// String names the kind, for rendering and error messages.
 50func (k Kind) String() string {
 51	switch k {
 52	case KindInt:
 53		return "int"
 54	case KindString:
 55		return "string"
 56	case KindList:
 57		return "list"
 58	case KindDict:
 59		return "dict"
 60	default:
 61		return "invalid"
 62	}
 63}
 64
 65// Errors returned by [Decode]. They are distinguishable on purpose: a caller
 66// feeding the decoder a user-pasted torrent wants to say which of the four
 67// strictness rules the paste broke.
 68var (
 69	// ErrTooLong is returned when input is longer than [MaxLen].
 70	ErrTooLong = errors.New("bencode: input too long")
 71	// ErrSyntax is returned when input is not bencode at all.
 72	ErrSyntax = errors.New("bencode: malformed input")
 73	// ErrNotCanonical is returned for input that is parseable but could never
 74	// have been produced by an encoder: a leading zero, a negative zero, or
 75	// dictionary keys that are unsorted or duplicated.
 76	ErrNotCanonical = errors.New("bencode: input is not canonical")
 77	// ErrTrailingData is returned when bytes follow the top-level value.
 78	ErrTrailingData = errors.New("bencode: trailing data after top-level value")
 79	// ErrTooDeep is returned when nesting exceeds [MaxDepth].
 80	ErrTooDeep = errors.New("bencode: nesting too deep")
 81)
 82
 83// Value is one bencode value. Build one with [NewInt], [NewString], [NewList]
 84// or [NewDict], or get one from [Decode]. Accessors that do not match the
 85// value's kind return the zero value rather than panicking, so a chain of
 86// lookups through a document of unknown shape never aborts a realm call.
 87type Value struct {
 88	kind  Kind
 89	num   int64
 90	text  string
 91	elems []*Value
 92	keys  []string
 93	vals  []*Value
 94}
 95
 96// NewInt returns an integer value.
 97func NewInt(n int64) *Value { return &Value{kind: KindInt, num: n} }
 98
 99// NewString returns a byte-string value.
100func NewString(s string) *Value { return &Value{kind: KindString, text: s} }
101
102// NewList returns a list of the given items, in order. A nil item, and the
103// zero Value, are dropped: both encode to nothing, which would turn a three
104// item list into a two item encoding that still reports a length of three.
105func NewList(items ...*Value) *Value {
106	l := &Value{kind: KindList, elems: []*Value{}}
107	for _, it := range items {
108		if it.Kind() == KindInvalid {
109			continue
110		}
111		l.elems = append(l.elems, it)
112	}
113	return l
114}
115
116// NewDict returns an empty dictionary. Fill it with [Value.Set], in any order:
117// the encoding sorts.
118func NewDict() *Value {
119	return &Value{kind: KindDict, keys: []string{}, vals: []*Value{}}
120}
121
122// Kind reports the value's type. A nil value is [KindInvalid].
123func (v *Value) Kind() Kind {
124	if v == nil {
125		return KindInvalid
126	}
127	return v.kind
128}
129
130// Int returns the integer, or 0 for any other kind.
131func (v *Value) Int() int64 {
132	if v == nil || v.kind != KindInt {
133		return 0
134	}
135	return v.num
136}
137
138// Text returns the byte string, or "" for any other kind.
139func (v *Value) Text() string {
140	if v == nil || v.kind != KindString {
141		return ""
142	}
143	return v.text
144}
145
146// Len returns the number of list items or dictionary entries, 0 otherwise.
147func (v *Value) Len() int {
148	if v == nil {
149		return 0
150	}
151	switch v.kind {
152	case KindList:
153		return len(v.elems)
154	case KindDict:
155		return len(v.keys)
156	default:
157		return 0
158	}
159}
160
161// At returns the i-th list item, or the i-th dictionary value in key order.
162// Out of range, or any other kind, returns nil.
163func (v *Value) At(i int) *Value {
164	if v == nil || i < 0 {
165		return nil
166	}
167	switch v.kind {
168	case KindList:
169		if i >= len(v.elems) {
170			return nil
171		}
172		return v.elems[i]
173	case KindDict:
174		if i >= len(v.vals) {
175			return nil
176		}
177		return v.vals[i]
178	default:
179		return nil
180	}
181}
182
183// Get returns the dictionary entry for key, or nil when it is absent or the
184// value is not a dictionary.
185func (v *Value) Get(key string) *Value {
186	if v == nil || v.kind != KindDict {
187		return nil
188	}
189	i, found := v.find(key)
190	if !found {
191		return nil
192	}
193	return v.vals[i]
194}
195
196// Keys returns the dictionary's keys in bytewise order, nil for other kinds.
197func (v *Value) Keys() []string {
198	if v == nil || v.kind != KindDict {
199		return nil
200	}
201	out := make([]string, len(v.keys))
202	copy(out, v.keys)
203	return out
204}
205
206// Set inserts or replaces a dictionary entry and returns the dictionary, so
207// calls chain. Four things are refused rather than stored, each because it
208// would make the encoding disagree with the structure: a receiver that is not
209// a dictionary, a nil value, the zero Value, and the dictionary itself. The
210// first three encode to nothing, which would emit a key with no value and
211// produce a dictionary this package's own Decode rejects; the fourth is a
212// cycle. Removing an entry is deliberately not spelled "set it to nil",
213// because nothing here removes.
214//
215// An indirect cycle (two dictionaries holding each other) is not detectable
216// here without walking the whole structure on every insert, so it is caught by
217// [Value.Encode] instead, which is depth-bounded and returns "".
218//
219// It never writes through the slices a previous Set produced. gno lets a
220// caller copy the struct behind the pointer, and two copies sharing a backing
221// array would see each other's replacements but not each other's insertions.
222func (v *Value) Set(key string, val *Value) *Value {
223	if v == nil || v.kind != KindDict || val.Kind() == KindInvalid || val == v {
224		return v
225	}
226	i, found := v.find(key)
227	rest := i
228	if found {
229		rest = i + 1
230	}
231	keys := make([]string, 0, len(v.keys)+1)
232	vals := make([]*Value, 0, len(v.vals)+1)
233	keys = append(append(append(keys, v.keys[:i]...), key), v.keys[rest:]...)
234	vals = append(append(append(vals, v.vals[:i]...), val), v.vals[rest:]...)
235	v.keys, v.vals = keys, vals
236	return v
237}
238
239// find returns the index of key, or where it would be inserted.
240func (v *Value) find(key string) (int, bool) {
241	lo, hi := 0, len(v.keys)
242	for lo < hi {
243		mid := (lo + hi) / 2
244		if v.keys[mid] < key {
245			lo = mid + 1
246		} else {
247			hi = mid
248		}
249	}
250	return lo, lo < len(v.keys) && v.keys[lo] == key
251}
252
253// Encode returns the canonical bencoding of the value, or "" for a value that
254// has no canonical encoding: a nil, the zero Value, anything nested deeper
255// than [MaxDepth], and therefore any cycle a caller assembled by hand. "" is
256// not a legal bencode document, so a caller can test for it.
257//
258// Encode has no error to return and is called from a realm's Render, so it is
259// total by construction: the depth bound is what keeps a structure the decoder
260// could never have produced from aborting the call that encodes it.
261func (v *Value) Encode() string {
262	var b strings.Builder
263	if !v.writeTo(&b, 0) {
264		return ""
265	}
266	return b.String()
267}
268
269// writeTo reports whether the whole value fit within MaxDepth. The bound is
270// counted on containers only, exactly as the decoder counts it, so the two
271// agree about which structures exist. A false leaves b holding a partial
272// encoding, which is why Encode discards it.
273func (v *Value) writeTo(b *strings.Builder, depth int) bool {
274	if v == nil {
275		return true
276	}
277	switch v.kind {
278	case KindInt:
279		b.WriteString("i")
280		b.WriteString(strconv.FormatInt(v.num, 10))
281		b.WriteString("e")
282	case KindString:
283		b.WriteString(strconv.Itoa(len(v.text)))
284		b.WriteString(":")
285		b.WriteString(v.text)
286	case KindList:
287		if depth >= MaxDepth {
288			return false
289		}
290		b.WriteString("l")
291		for _, e := range v.elems {
292			if !e.writeTo(b, depth+1) {
293				return false
294			}
295		}
296		b.WriteString("e")
297	case KindDict:
298		if depth >= MaxDepth {
299			return false
300		}
301		b.WriteString("d")
302		for i, k := range v.keys {
303			b.WriteString(strconv.Itoa(len(k)))
304			b.WriteString(":")
305			b.WriteString(k)
306			if !v.vals[i].writeTo(b, depth+1) {
307				return false
308			}
309		}
310		b.WriteString("e")
311	}
312	return true
313}
314
315// Decode parses one bencode value and rejects anything after it. It also
316// rejects input that is parseable but not canonical, which is the whole point:
317// see the package doc.
318func Decode(s string) (*Value, error) {
319	if len(s) > MaxLen {
320		return nil, ErrTooLong
321	}
322	v, next, err := decodeValue(s, 0, 0)
323	if err != nil {
324		return nil, err
325	}
326	if next != len(s) {
327		return nil, ErrTrailingData
328	}
329	return v, nil
330}
331
332func decodeValue(s string, i, depth int) (*Value, int, error) {
333	if i >= len(s) {
334		return nil, i, ErrSyntax
335	}
336	switch c := s[i]; {
337	case c == 'i':
338		return decodeInt(s, i)
339	case c == 'l':
340		return decodeList(s, i, depth)
341	case c == 'd':
342		return decodeDict(s, i, depth)
343	case c >= '0' && c <= '9':
344		return decodeString(s, i)
345	default:
346		return nil, i, ErrSyntax
347	}
348}
349
350func decodeInt(s string, i int) (*Value, int, error) {
351	end := strings.IndexByte(s[i:], 'e')
352	if end < 0 {
353		return nil, i, ErrSyntax
354	}
355	end += i
356	body := s[i+1 : end]
357	if err := checkIntLiteral(body); err != nil {
358		return nil, i, err
359	}
360	n, err := strconv.ParseInt(body, 10, 64)
361	if err != nil {
362		return nil, i, ErrSyntax
363	}
364	return NewInt(n), end + 1, nil
365}
366
367// checkIntLiteral enforces the canonical integer grammar: optional '-', then
368// digits, with no leading zero and no negative zero.
369func checkIntLiteral(body string) error {
370	digits := body
371	neg := false
372	if strings.HasPrefix(digits, "-") {
373		neg = true
374		digits = digits[1:]
375	}
376	if digits == "" {
377		return ErrSyntax
378	}
379	for k := 0; k < len(digits); k++ {
380		if digits[k] < '0' || digits[k] > '9' {
381			return ErrSyntax
382		}
383	}
384	if len(digits) > 1 && digits[0] == '0' {
385		return ErrNotCanonical
386	}
387	if neg && digits == "0" {
388		return ErrNotCanonical
389	}
390	return nil
391}
392
393func decodeString(s string, i int) (*Value, int, error) {
394	colon := strings.IndexByte(s[i:], ':')
395	if colon < 0 {
396		return nil, i, ErrSyntax
397	}
398	colon += i
399	lit := s[i:colon]
400	for k := 0; k < len(lit); k++ {
401		if lit[k] < '0' || lit[k] > '9' {
402			return nil, i, ErrSyntax
403		}
404	}
405	if len(lit) > 1 && lit[0] == '0' {
406		return nil, i, ErrNotCanonical
407	}
408	n, err := strconv.Atoi(lit)
409	if err != nil || n < 0 {
410		return nil, i, ErrSyntax
411	}
412	start := colon + 1
413	// Compare against what is left rather than computing start+n: the length
414	// literal is bounded only by MaxLen, so a 19-digit length fits in the
415	// input and in an int64, and the sum would wrap to a negative slice bound.
416	if n > len(s)-start {
417		return nil, i, ErrSyntax
418	}
419	return NewString(s[start : start+n]), start + n, nil
420}
421
422func decodeList(s string, i, depth int) (*Value, int, error) {
423	if depth+1 > MaxDepth {
424		return nil, i, ErrTooDeep
425	}
426	l := NewList()
427	j := i + 1
428	for {
429		if j >= len(s) {
430			return nil, j, ErrSyntax
431		}
432		if s[j] == 'e' {
433			return l, j + 1, nil
434		}
435		item, next, err := decodeValue(s, j, depth+1)
436		if err != nil {
437			return nil, next, err
438		}
439		l.elems = append(l.elems, item)
440		j = next
441	}
442}
443
444func decodeDict(s string, i, depth int) (*Value, int, error) {
445	if depth+1 > MaxDepth {
446		return nil, i, ErrTooDeep
447	}
448	d := NewDict()
449	j := i + 1
450	last := ""
451	for {
452		if j >= len(s) {
453			return nil, j, ErrSyntax
454		}
455		if s[j] == 'e' {
456			return d, j + 1, nil
457		}
458		if s[j] < '0' || s[j] > '9' {
459			// A key is always a byte string. Anything else is not a dict.
460			return nil, j, ErrSyntax
461		}
462		kv, next, err := decodeString(s, j)
463		if err != nil {
464			return nil, next, err
465		}
466		key := kv.Text()
467		if len(d.keys) > 0 && key <= last {
468			// Unsorted or duplicated: parseable, but no encoder emits it.
469			return nil, next, ErrNotCanonical
470		}
471		val, next2, err := decodeValue(s, next, depth+1)
472		if err != nil {
473			return nil, next2, err
474		}
475		d.keys = append(d.keys, key)
476		d.vals = append(d.vals, val)
477		last = key
478		j = next2
479	}
480}