/// <summary> /// Unquote a string. /// </summary> /// <param name="s"></param> /// <returns></returns> public static string Unquote(string s) { if (s == null) { return(null); } if (s.Length < 2) { return(s); } char first = s[0]; char last = s[s.Length - 1]; if (first != last || (first != '"' && first != '\'')) { return(s); } StringBuilder b = new StringBuilder(s.Length - 2); lock (b) { bool escape = false; for (int i = 1; i < s.Length - 1; i++) { char c = s[i]; if (escape) { escape = false; switch (c) { case 'n': b.Append('\n'); break; case 'r': b.Append('\r'); break; case 't': b.Append('\t'); break; case 'f': b.Append('\f'); break; case 'b': b.Append('\b'); break; case 'u': b.Append((char)( (TypeUtil.ConvertHexDigit((byte)s[i++]) << 24) + (TypeUtil.ConvertHexDigit((byte)s[i++]) << 16) + (TypeUtil.ConvertHexDigit((byte)s[i++]) << 8) + (TypeUtil.ConvertHexDigit((byte)s[i++])) ) ); break; default: b.Append(c); break; } } else if (c == '\\') { escape = true; continue; } else { b.Append(c); } } return(b.ToString()); } }
/// <summary> /// Decode string with % encoding. /// This method makes the assumption that the majority of calls /// will need no decoding. /// </summary> /// <param name="encoded"></param> /// <param name="offset"></param> /// <param name="length"></param> /// <param name="charset"></param> /// <returns></returns> public static string DecodeString(string encoded, int offset, int length, string charset) { if (charset == null || StringUtil.IsUTF8(charset)) { Utf8StringBuffer buffer = null; for (int i = 0; i < length; i++) { char c = encoded[offset + i]; if (c < 0 || c > 0xff) { if (buffer == null) { buffer = new Utf8StringBuffer(length); buffer.Append(encoded, offset, i + 1); } else { buffer.Append((byte)c); } } else if (c == '+') { if (buffer == null) { buffer = new Utf8StringBuffer(length); buffer.Append(encoded, offset, i); } buffer.Append((byte)' '); } else if (c == '%' && (i + 2) < length) { if (buffer == null) { buffer = new Utf8StringBuffer(length); buffer.Append(encoded, offset, i); } while (c == '%' && (i + 2) < length) { try { byte b = (byte)TypeUtil.ParseInt(encoded, offset + i + 1, 2, 16); buffer.Append(b); i += 3; } catch (FormatException) { buffer.Append('%'); for (char next; ((next = encoded[++i + offset]) != '%');) { buffer.Append((next == '+' ? ' ' : next)); } } if (i < length) { c = encoded[offset + i]; } } i--; } else if (buffer != null) { buffer.Append((byte)c); } } if (buffer == null) { if (offset == 0 && encoded.Length == length) { return(encoded); } return(encoded.Substring(offset, length)); } return(buffer.ToString()); } else { StringBuilder buffer = null; try { for (int i = 0; i < length; i++) { char c = encoded[offset + i]; if (c < 0 || c > 0xff) { if (buffer == null) { buffer = new StringBuilder(length); buffer.Append(encoded, offset, i + 1); } else { buffer.Append(c); } } else if (c == '+') { if (buffer == null) { buffer = new StringBuilder(length); buffer.Append(encoded, offset, i); } buffer.Append(' '); } else if (c == '%' && (i + 2) < length) { if (buffer == null) { buffer = new StringBuilder(length); buffer.Append(encoded, offset, i); } byte[] ba = new byte[length]; int n = 0; while (c >= 0 && c <= 0xff) { if (c == '%') { if (i + 2 < length) { try { ba[n++] = (byte)TypeUtil.ParseInt(encoded, offset + i + 1, 2, 16); i += 3; } catch (FormatException) { ba[n - 1] = (byte)'%'; for (char next; ((next = encoded[++i + offset]) != '%');) { ba[n++] = (byte)(next == '+' ? ' ' : next); } } } else { ba[n++] = (byte)'%'; i++; } } else if (c == '+') { ba[n++] = (byte)' '; i++; } else { ba[n++] = (byte)c; i++; } if (i >= length) { break; } c = encoded[offset + i]; } i--; string str = Encoding.GetEncoding(charset).GetString(ba, 0, n); buffer.Append(str); } else if (buffer != null) { buffer.Append(c); } } if (buffer == null) { if (offset == 0 && encoded.Length == length) { return(encoded); } return(encoded.Substring(offset, length)); } return(buffer.ToString()); } catch (ArgumentException e) { throw new SystemException(e.Message, e); } } }
/// <summary> /// Decoded parameters to Map. /// </summary> /// <param name="input">InputSteam to read</param> /// <param name="map">MultiMap to Add parameters to</param> /// <param name="maxLength">maximum length of conent to read 0r -1 for no limit</param> public static void DecodeUtf8To(Stream input, MultiMap <string> map, int maxLength) { lock (map) { Utf8StringBuilder buffer = new Utf8StringBuilder(); string key = null; string value = null; int b; // TODO cache of parameter names ??? int totalLength = 0; while ((b = input.ReadByte()) >= 0) { switch ((char)b) { case '&': value = buffer.Length == 0 ? "" : buffer.ToString(); buffer.Reset(); if (key != null) { map.Append(key, value); } else if (value != null && value.Length > 0) { map.Append(value, ""); } key = null; value = null; break; case '=': if (key != null) { buffer.Append((byte)b); break; } key = buffer.ToString(); buffer.Reset(); break; case '+': buffer.Append((byte)' '); break; case '%': int dh = input.ReadByte(); int dl = input.ReadByte(); if (dh < 0 || dl < 0) { break; } buffer.Append((byte)((TypeUtil.ConvertHexDigit((byte)dh) << 4) + TypeUtil.ConvertHexDigit((byte)dl))); break; default: buffer.Append((byte)b); break; } if (maxLength >= 0 && (++totalLength > maxLength)) { throw new InvalidOperationException("Form too large"); } } if (key != null) { value = buffer.Length == 0 ? "" : buffer.ToString(); buffer.Reset(); map.Append(key, value); } else if (buffer.Length > 0) { map.Append(buffer.ToString(), ""); } } }
/// <summary> /// Decoded parameters to Map. /// </summary> /// <param name="input">the stream containing the encoded parameters</param> /// <param name="map"></param> /// <param name="charset"></param> /// <param name="maxLength"></param> public static void DecodeTo(Stream input, MultiMap <string> map, string charset, int maxLength) { if (charset == null || StringUtil.__ISO_8859_1.Equals(charset)) { Decode88591To(input, map, maxLength); return; } if (StringUtil.__UTF8.Equals(charset, StringComparison.OrdinalIgnoreCase)) { DecodeUtf8To(input, map, maxLength); return; } if (StringUtil.__UTF16.Equals(charset, StringComparison.OrdinalIgnoreCase)) // Should be all 2 byte encodings { DecodeUtf16To(input, map, maxLength); return; } lock (map) { string key = null; string value = null; int c; int digit = 0; int digits = 0; int totalLength = 0; ByteArrayOutputStream2 output = new ByteArrayOutputStream2(); input.Position = 0; long size = 0; while ((c = input.ReadByte()) > 0) { switch ((char)c) { case '&': size = output.Length; value = size == 0 ? "" : Encoding.GetEncoding(charset).GetString(output.GetBuffer(), 0, (int)size); output.Position = 0; if (key != null) { map.Append(key, value); } else if (value != null && value.Length > 0) { map.Append(value, ""); } key = null; value = null; break; case '=': if (key != null) { output.WriteByte(c); break; } size = output.Length; key = size == 0 ? "" : Encoding.GetEncoding(charset).GetString(output.GetBuffer(), 0, (int)size); output.Position = 0; break; case '+': output.WriteByte(' '); break; case '%': digits = 2; break; default: if (digits == 2) { digit = TypeUtil.ConvertHexDigit((byte)c); digits = 1; } else if (digits == 1) { int v = (byte)(digit << 4) + TypeUtil.ConvertHexDigit((byte)c); output.WriteByte(v); digits = 0; } else { output.WriteByte((byte)c); } break; } totalLength++; if (maxLength >= 0 && totalLength > maxLength) { throw new InvalidOperationException("Form too large"); } } size = output.Length; if (key != null) { value = size == 0 ? "" : Encoding.GetEncoding(charset).GetString(output.GetBuffer(), 0, (int)size); output.Position = 0; map.Append(key, value); } else if (size > 0) { map.Append(Encoding.GetEncoding(charset).GetString(output.GetBuffer(), 0, (int)size), ""); } } }
/* -------------------------------------------------------------- */ /** Decoded parameters to Map. * @param data the byte[] containing the encoded parameters */ public static void DecodeUtf8To(byte[] raw, int offset, int length, MultiMap <string> map, Utf8StringBuilder buffer) { lock (map) { string key = null; string value = null; // TODO cache of parameter names ??? int end = offset + length; for (int i = offset; i < end; i++) { byte b = raw[i]; switch ((char)(0xff & b)) { case '&': value = buffer.Length == 0 ? "" : buffer.ToString(); buffer.Reset(); if (key != null) { map.Append(key, value); } else if (value != null && value.Length > 0) { map.Append(value, ""); } key = null; value = null; break; case '=': if (key != null) { buffer.Append(b); break; } key = buffer.ToString(); buffer.Reset(); break; case '+': buffer.Append((byte)' '); break; case '%': if (i + 2 < end) { buffer.Append((byte)((TypeUtil.ConvertHexDigit(raw[++i]) << 4) + TypeUtil.ConvertHexDigit(raw[++i]))); } break; default: buffer.Append(b); break; } } if (key != null) { value = buffer.Length == 0 ? "" : buffer.ToString(); buffer.Reset(); map.Append(key, value); } else if (buffer.Length > 0) { map.Append(buffer.ToString(), ""); } } }