UrlEscape

object UrlEscape

URL percent-encoding / decoding, pure Kotlin so it runs in commonMain on every target.

Direct port of libtorrent's escape_string / escape_path / unescape_string / need_encoding (src/escape_string.cpp). These drive tracker GET requests (where the 20-byte binary info-hash and peer-id are percent-encoded into the query string) and magnet/URL parsing.

libtorrent keeps a single unreserved_chars table and indexes into it at different offsets so the three operations share one set:

index:  0..1   "%+"
2..10 ";?:@=&,$/" (reserved)
11..18 "-_!.~*()" (unreserved specials; note ' is excluded
because some buggy trackers reject it)
19.. A-Z a-z 0-9 (alphanumerics)
  • escape (libtorrent escape_string) starts at offset 11: it keeps only -_!.~*() and the alphanumerics, percent-encoding everything else, including /, :, ?, &, % and so on. This is what you use to encode an individual query-string value.

  • escapePath (libtorrent escape_path) starts at offset 10: identical to escape except / is also left intact, so a whole path can be escaped without mangling its separators.

  • needsEncoding (libtorrent need_encoding) starts at offset 0: returns true if the string contains anything outside the full table (so %, +, and the reserved set all count as "fine"). Used to decide whether a URL even needs touching.

A subtle detail faithfully reproduced from the C++: the table test also requires *str != 0, i.e. a NUL byte is always escaped (to %00) even though C's strchr would otherwise treat the terminating NUL as a match.

Output hex digits are lowercase, matching libtorrent's aux::hex_chars.

Functions

Link copied to clipboard

Percent-encode the text s (libtorrent escape_string). Everything except -_!.~*() and [A-Za-z0-9] is escaped.

Link copied to clipboard

Percent-encode the path text s (libtorrent escape_path). Same as escape but / is preserved.

Link copied to clipboard

Percent-encode raw bytes as a path (libtorrent escape_path); / preserved.

Link copied to clipboard

Percent-encode arbitrary raw bytes (libtorrent escape_string over a char const*). This is the form used for binary values such as the 20-byte info-hash or peer-id in a tracker announce query.

Link copied to clipboard

Byte-array form of needsEncoding (libtorrent need_encoding).

True if s (interpreted as its UTF-8 bytes) contains any character that would have to be percent-encoded in a URL: libtorrent need_encoding. %, + and the reserved set do not count as needing encoding.

Link copied to clipboard

Decode a percent-encoded string s (libtorrent unescape_string).

Link copied to clipboard

Like unescape but returns the raw decoded bytes. libtorrent's unescape_string operates byte-wise on a std::string; this is the faithful byte-level form, which matters when the decoded payload is binary (an info-hash percent-encoded into a magnet/tracker URL is not valid UTF-8).