You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
4.6 KiB
154 lines
4.6 KiB
//
|
|
// System.Web.HttpUtility/HttpEncoder
|
|
//
|
|
// Authors:
|
|
// Patrik Torstensson (Patrik.Torstensson@labs2.com)
|
|
// Wictor Wilén (decode/encode functions) (wictor@ibizkit.se)
|
|
// Tim Coleman (tim@timcoleman.com)
|
|
using System;
|
|
using System.Text;
|
|
using System.IO;
|
|
using System.Collections.Generic;
|
|
|
|
namespace MonoTorrent
|
|
{
|
|
static class UriHelper
|
|
{
|
|
static readonly char [] hexChars = "0123456789abcdef".ToCharArray ();
|
|
|
|
public static string UrlEncode (byte[] bytes)
|
|
{
|
|
if (bytes == null)
|
|
throw new ArgumentNullException ("bytes");
|
|
|
|
var result = new MemoryStream (bytes.Length);
|
|
for (int i = 0; i < bytes.Length; i++)
|
|
UrlEncodeChar ((char)bytes [i], result, false);
|
|
|
|
return Encoding.ASCII.GetString (result.ToArray());
|
|
}
|
|
|
|
public static byte [] UrlDecode (string s)
|
|
{
|
|
if (null == s)
|
|
return null;
|
|
|
|
var e = Encoding.UTF8;
|
|
if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1)
|
|
return e.GetBytes (s);
|
|
|
|
long len = s.Length;
|
|
var bytes = new List <byte> ();
|
|
int xchar;
|
|
char ch;
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
ch = s [i];
|
|
if (ch == '%' && i + 2 < len && s [i + 1] != '%') {
|
|
if (s [i + 1] == 'u' && i + 5 < len) {
|
|
// unicode hex sequence
|
|
xchar = GetChar (s, i + 2, 4);
|
|
if (xchar != -1) {
|
|
WriteCharBytes (bytes, (char)xchar, e);
|
|
i += 5;
|
|
} else
|
|
WriteCharBytes (bytes, '%', e);
|
|
} else if ((xchar = GetChar (s, i + 1, 2)) != -1) {
|
|
WriteCharBytes (bytes, (char)xchar, e);
|
|
i += 2;
|
|
} else {
|
|
WriteCharBytes (bytes, '%', e);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (ch == '+')
|
|
WriteCharBytes (bytes, ' ', e);
|
|
else
|
|
WriteCharBytes (bytes, ch, e);
|
|
}
|
|
|
|
return bytes.ToArray ();
|
|
}
|
|
|
|
static void UrlEncodeChar (char c, Stream result, bool isUnicode) {
|
|
if (c > ' ' && NotEncoded (c)) {
|
|
result.WriteByte ((byte)c);
|
|
return;
|
|
}
|
|
if (c==' ') {
|
|
result.WriteByte ((byte)'+');
|
|
return;
|
|
}
|
|
if ( (c < '0') ||
|
|
(c < 'A' && c > '9') ||
|
|
(c > 'Z' && c < 'a') ||
|
|
(c > 'z')) {
|
|
if (isUnicode && c > 127) {
|
|
result.WriteByte ((byte)'%');
|
|
result.WriteByte ((byte)'u');
|
|
result.WriteByte ((byte)'0');
|
|
result.WriteByte ((byte)'0');
|
|
}
|
|
else
|
|
result.WriteByte ((byte)'%');
|
|
|
|
int idx = ((int) c) >> 4;
|
|
result.WriteByte ((byte)hexChars [idx]);
|
|
idx = ((int) c) & 0x0F;
|
|
result.WriteByte ((byte)hexChars [idx]);
|
|
}
|
|
else {
|
|
result.WriteByte ((byte)c);
|
|
}
|
|
}
|
|
|
|
static int GetChar (string str, int offset, int length)
|
|
{
|
|
int val = 0;
|
|
int end = length + offset;
|
|
for (int i = offset; i < end; i++) {
|
|
char c = str [i];
|
|
if (c > 127)
|
|
return -1;
|
|
|
|
int current = GetInt ((byte) c);
|
|
if (current == -1)
|
|
return -1;
|
|
val = (val << 4) + current;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
static int GetInt (byte b)
|
|
{
|
|
char c = (char) b;
|
|
if (c >= '0' && c <= '9')
|
|
return c - '0';
|
|
|
|
if (c >= 'a' && c <= 'f')
|
|
return c - 'a' + 10;
|
|
|
|
if (c >= 'A' && c <= 'F')
|
|
return c - 'A' + 10;
|
|
|
|
return -1;
|
|
}
|
|
|
|
static bool NotEncoded (char c)
|
|
{
|
|
return c == '!' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_' || c == '\'';
|
|
}
|
|
|
|
static void WriteCharBytes (List<byte> buf, char ch, Encoding e)
|
|
{
|
|
if (ch > 255) {
|
|
foreach (byte b in e.GetBytes (new char[] { ch }))
|
|
buf.Add (b);
|
|
} else
|
|
buf.Add ((byte)ch);
|
|
}
|
|
}
|
|
}
|