/// <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), ""); } } }
/// <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(), ""); } } }
/* -------------------------------------------------------------- */ /** 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(), ""); } } }
/// <summary> /// Decoded parameters to Map. /// </summary> /// <param name="raw">the byte[] containing the encoded parameters</param> /// <param name="offset"></param> /// <param name="length"></param> /// <param name="map"></param> public static void DecodeUtf8To(byte[] raw, int offset, int length, MultiMap <string> map) { DecodeUtf8To(raw, offset, length, map, new Utf8StringBuilder()); }
/// <summary> /// Decoded parameters to Map. /// </summary> /// <param name="content">the string containing the encoded parameters</param> /// <param name="map"></param> /// <param name="charset"></param> public static void DecodeTo(string content, MultiMap <string> map, string charset) { if (charset == null) { charset = StringUtil.__UTF8; } lock (map) { string key = null; string value = null; int mark = -1; bool encoded = false; for (int i = 0; i < content.Length; i++) { char c = content[i]; switch (c) { case '&': int l = i - mark - 1; value = l == 0 ? "" : (encoded ? DecodeString(content, mark + 1, l, charset) : content.Substring(mark + 1, i - (mark + 1))); mark = i; encoded = false; 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) { break; } key = encoded ? DecodeString(content, mark + 1, i - mark - 1, charset) : content.Substring(mark + 1, i - (mark + 1)); mark = i; encoded = false; break; case '+': encoded = true; break; case '%': encoded = true; break; } } if (key != null) { int l = content.Length - mark - 1; value = l == 0 ? "" : (encoded ? DecodeString(content, mark + 1, l, charset) : content.Substring(mark + 1)); map.Append(key, value); } else if (mark < content.Length) { key = encoded ? DecodeString(content, mark + 1, content.Length - mark - 1, charset) : content.Substring(mark + 1); map.Append(key, ""); } } }
/// <summary> /// Encode Hashtable with % encoding. /// </summary> /// <param name="map">multimap values to encode</param> /// <param name="charset">Characterset Encoding</param> /// <param name="equalsForNullValue">if True, then an '=' is always used, even /// for parameters without a value. e.g. "blah?a=&b=&c=". /// </param> /// <returns>Encoded string Value</returns> public static string Encode(MultiMap <string> map, string charset, bool equalsForNullValue) { if (charset == null) { charset = StringUtil.__UTF8; } StringBuilder result = new StringBuilder(128); bool first = true; foreach (string key in map.Keys) { if (!first) { result.Append('&'); } object list = map[key]; int s = LazyList.Size(list); if (s == 0) { result.Append(EncodeString(key, charset)); if (equalsForNullValue) { result.Append('='); } } else { for (int i = 0; i < s; i++) { if (i > 0) { result.Append('&'); } object val = LazyList.Get(list, i); result.Append(EncodeString(key, charset)); if (val != null) { string str = val.ToString(); if (str.Length > 0) { result.Append('='); result.Append(EncodeString(str, charset)); } else if (equalsForNullValue) { result.Append('='); } } else if (equalsForNullValue) { result.Append('='); } } } first = false; } return(result.ToString()); }