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 }