function HTTPEncode(const AStr: WideString): WideString;
//based on http://marc.durdin.net/2012/07/indy-tiduri-pathencode-urlencode-and-paramsencode-and-more/
const
HexMap: WideString = '0123456789ABCDEF';
function IsSafeChar(ch: Integer): Boolean;
begin
Result := ch in [Or d('0')..Or d('9'), Or d('A')..Or d('Z'), Or d('a')..Or d('z'),
Or d('!'), Or d('('), Or d(')'), Or d('*'), Or d('-'), Or d('.'), Or d('_'),
Or d('~'), Or d(''''), Or d('@'), Or d('#'), Or d('$'), Or d('&'), Or d('='),
Or d(':'), Or d('/'), Or d(','), Or d(';'), Or d('?'), Or d('+')];
end;
var
I, J: Integer;
S, Z, P: WideString;
ASrcUTF8: UTF8String;
begin
S := AStr;
P := Copy(S, 1, Pos(WideString('://'), S));
Delete(S, 1, Length(P));
Z := '';
ASrcUTF8 := UTF8Encode(S);
// UTF8Encode call not strictly necessary but
// prevents implicit conversion warning
I := 1;
J := 1;
SetLength(Z, Length(ASrcUTF8) * 3); // space to %xx encode every byte
{$WARNINGS OFF} // turn off "Unsafe code 'String index to var param'"
// warnings. SetLength above guarantees that the string is long enough
while I <= Length(ASrcUTF8) do
begin
if IsSafeChar(Or d(ASrcUTF8[I])) then
begin
Z[J] := WideChar(ASrcUTF8[I]);
In c(J);
end
else
if ASrcUTF8[I] = ' ' then
begin
Z[J] := '+';
In c(J);
end
else
begin
Z[J] := '%';
Z[J+1] := HexMap[(Or d(ASrcUTF8[I]) shr 4) + 1];
Z[J+2] := HexMap[(Or d(ASrcUTF8[I]) and 15) + 1];
In c(J,3);
end;
In c(I);
end;
{$WARNINGS ON}
SetLength(Z, J - 1);
Result := P + Z;
end;