summaryrefslogtreecommitdiff
path: root/vendor/github.com/godbus/dbus/v5/escape.go
blob: d1509d945818ed10aa5574bfb02ab22cae4a60c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package dbus

import "net/url"

// EscapeBusAddressValue implements a requirement to escape the values
// in D-Bus server addresses, as defined by the D-Bus specification at
// https://dbus.freedesktop.org/doc/dbus-specification.html#addresses.
func EscapeBusAddressValue(val string) string {
	toEsc := strNeedsEscape(val)
	if toEsc == 0 {
		// Avoid unneeded allocation/copying.
		return val
	}

	// Avoid allocation for short paths.
	var buf [64]byte
	var out []byte
	// Every to-be-escaped byte needs 2 extra bytes.
	required := len(val) + 2*toEsc
	if required <= len(buf) {
		out = buf[:required]
	} else {
		out = make([]byte, required)
	}

	j := 0
	for i := 0; i < len(val); i++ {
		if ch := val[i]; needsEscape(ch) {
			// Convert ch to %xx, where xx is hex value.
			out[j] = '%'
			out[j+1] = hexchar(ch >> 4)
			out[j+2] = hexchar(ch & 0x0F)
			j += 3
		} else {
			out[j] = ch
			j++
		}
	}

	return string(out)
}

// UnescapeBusAddressValue unescapes values in D-Bus server addresses,
// as defined by the D-Bus specification at
// https://dbus.freedesktop.org/doc/dbus-specification.html#addresses.
func UnescapeBusAddressValue(val string) (string, error) {
	// Looks like url.PathUnescape does exactly what is required.
	return url.PathUnescape(val)
}

// hexchar returns an octal representation of a n, where n < 16.
// For invalid values of n, the function panics.
func hexchar(n byte) byte {
	const hex = "0123456789abcdef"

	// For n >= len(hex), runtime will panic.
	return hex[n]
}

// needsEscape tells if a byte is NOT one of optionally-escaped bytes.
func needsEscape(c byte) bool {
	if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
		return false
	}
	switch c {
	case '-', '_', '/', '\\', '.', '*':
		return false
	}

	return true
}

// strNeedsEscape tells how many bytes in the string need escaping.
func strNeedsEscape(val string) int {
	count := 0

	for i := 0; i < len(val); i++ {
		if needsEscape(val[i]) {
			count++
		}
	}

	return count
}