static string DecodeComponent(string s, int from, int toExcluded, Encoding charset, bool isPath) { int len = toExcluded - from; if (len <= 0) { return(StringUtil.EmptyString); } int firstEscaped = -1; for (int i = from; i < toExcluded; i++) { char c = s[i]; if (c == HttpConstants.PercentChar || c == HttpConstants.PlusSignChar && !isPath) { firstEscaped = i; break; } } if (firstEscaped == -1) { return(s.Substring(from, len)); } // Each encoded byte takes 3 characters (e.g. "%20") int decodedCapacity = (toExcluded - firstEscaped) / 3; var byteBuf = new byte[decodedCapacity]; int idx; var strBuf = StringBuilderManager.Allocate(len); _ = strBuf.Append(s, from, firstEscaped - from); for (int i = firstEscaped; i < toExcluded; i++) { char c = s[i]; if (c != HttpConstants.PercentChar) { _ = strBuf.Append(c != HttpConstants.PlusSignChar || isPath ? c : StringUtil.Space); continue; } idx = 0; do { if (i + 3 > toExcluded) { StringBuilderManager.Free(strBuf); ThrowHelper.ThrowArgumentException_UnterminatedEscapeSeq(i, s); } byteBuf[idx++] = StringUtil.DecodeHexByte(s, i + 1); i += 3; }while (i < toExcluded && s[i] == HttpConstants.PercentChar); i--; _ = strBuf.Append(charset.GetString(byteBuf, 0, idx)); } return(StringBuilderManager.ReturnAndFree(strBuf)); }