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.
|
|
using Apewer; using System; using System.Collections.Generic; using System.Text;
namespace Apewer.Internals {
internal class UrlEncoding {
public static string Encode(string plain) { return TextUtility.FromBytes(Encode(TextUtility.Bytes(plain))); }
public static string Decode(string escaped) { return Decode(escaped, Encoding.UTF8); }
private UrlEncoding() { }
#region encode static
/// <summary>对 URL 编码。</summary>
static byte[] Encode(byte[] bytes) { if (bytes == null) return null; if (bytes.Length < 1) return BytesUtility.Empty;
var offset = 0; var count = bytes.Length;
int num = 0; int num2 = 0; for (int i = 0; i < count; i++) { char c = (char)bytes[offset + i]; if (c == ' ') { num++; } else if (!IsUrlSafeChar(c)) { num2++; } } if (num == 0 && num2 == 0) { if (offset == 0 && bytes.Length == count) { return bytes; } byte[] array = new byte[count]; Buffer.BlockCopy(bytes, offset, array, 0, count); return array; } byte[] array2 = new byte[count + num2 * 2]; int num3 = 0; for (int j = 0; j < count; j++) { byte b = bytes[offset + j]; char c2 = (char)b; if (IsUrlSafeChar(c2)) { array2[num3++] = b; } else if (c2 == ' ') { array2[num3++] = 43; } else { array2[num3++] = 37; array2[num3++] = (byte)IntToHex(b >> 4 & 0xF); array2[num3++] = (byte)IntToHex(b & 0xF); } } return array2; }
static bool IsUrlSafeChar(char ch) { //const string lower = "abcdefghijklmnopqrstuvwxyz";
//const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//const string numbers = "0123456789";
//const string symbols = "!()*-._";
if (ch >= 'a' && ch <= 'z') return true; if (ch >= 'A' && ch <= 'Z') return true; if (ch >= '0' && ch <= '9') return true; switch (ch) { case '!': case '(': case ')': case '*': case '-': case '.': case '_': return true; default: return false; } }
static char IntToHex(int n) { if (n <= 9) { return (char)(n + 48); } return (char)(n - 10 + 97); }
#endregion
#region decode instance
private int _bufferSize;
private int _numChars;
private char[] _charBuffer;
private int _numBytes;
private byte[] _byteBuffer;
private Encoding _encoding;
private void FlushBytes() { if (_numBytes > 0) { _numChars += _encoding.GetChars(_byteBuffer, 0, _numBytes, _charBuffer, _numChars); _numBytes = 0; } }
internal UrlEncoding(int bufferSize, Encoding encoding) { _bufferSize = bufferSize; _encoding = encoding; _charBuffer = new char[bufferSize]; }
internal void AddChar(char ch) { if (_numBytes > 0) { FlushBytes(); } _charBuffer[_numChars++] = ch; }
internal void AddByte(byte b) { if (_byteBuffer == null) { _byteBuffer = new byte[_bufferSize]; } _byteBuffer[_numBytes++] = b; }
internal string GetString() { if (_numBytes > 0) { FlushBytes(); } if (_numChars > 0) { return new string(_charBuffer, 0, _numChars); } return string.Empty; }
#endregion
#region decode static
static string Decode(string value, Encoding encoding) { if (value == null) { return null; } int length = value.Length; var urlDecoder = new UrlEncoding(length, encoding); for (int i = 0; i < length; i++) { char c = value[i]; switch (c) { case '+': c = ' '; goto default; case '%': if (i < length - 2) { if (value[i + 1] == 'u' && i < length - 5) { int num = HexToInt(value[i + 2]); int num2 = HexToInt(value[i + 3]); int num3 = HexToInt(value[i + 4]); int num4 = HexToInt(value[i + 5]); if (num >= 0 && num2 >= 0 && num3 >= 0 && num4 >= 0) { c = (char)(num << 12 | num2 << 8 | num3 << 4 | num4); i += 5; urlDecoder.AddChar(c); break; } } else { int num5 = HexToInt(value[i + 1]); int num6 = HexToInt(value[i + 2]); if (num5 >= 0 && num6 >= 0) { byte b = (byte)(num5 << 4 | num6); i += 2; urlDecoder.AddByte(b); break; } } } goto default; default: if ((c & 0xFF80) == 0) { urlDecoder.AddByte((byte)c); } else { urlDecoder.AddChar(c); } break; } } return ValidateString(urlDecoder.GetString()); }
static int HexToInt(char h) { if (h >= '0' && h <= '9') { return h - 48; } if (h >= 'a' && h <= 'f') { return h - 97 + 10; } if (h >= 'A' && h <= 'F') { return h - 65 + 10; } return -1; }
static string ValidateString(string input) { var skipUtf16Validation = true;
if (!skipUtf16Validation && !string.IsNullOrEmpty(input)) { int num = -1; int num2 = 0; while (num2 < input.Length) { if (!char.IsSurrogate(input[num2])) { num2++; continue; } num = num2; break; } if (num < 0) { return input; } char[] array = input.ToCharArray(); for (int i = num; i < array.Length; i++) { char c = array[i]; if (char.IsLowSurrogate(c)) { array[i] = '�'; } else if (char.IsHighSurrogate(c)) { if (i + 1 < array.Length && char.IsLowSurrogate(array[i + 1])) { i++; } else { array[i] = '�'; } } } return new string(array); } return input; }
#endregion
}
}
|