internal Unit(string input, char sep) { if (input == null || input == String.Empty) { type = (UnitType)0; value = 0.0; valueSet = false; return; } value = 0.0; double dv = 0, factor = .1; int i = 0; int count = input.Length; int sign = 1, unitStart = -1, unitLen = 0, wsCount = 0; char c; ParsingStage ps = ParsingStage.Trim; bool done = false, haveSep = false, haveDigits = false, isWhiteSpace; while (!done && i < count) { c = input [i]; switch (ps) { case ParsingStage.Trim: if (Char.IsWhiteSpace(c)) { i++; continue; } ps = ParsingStage.SignOrSep; continue; case ParsingStage.SignOrSep: wsCount = 0; if (c == '-') { sign = -1; i++; ps = ParsingStage.DigitOrSep; continue; } if (c == sep) { i++; haveSep = true; ps = ParsingStage.DigitOrUnit; dv = 0; continue; } if (Char.IsDigit(c)) { ps = ParsingStage.DigitOrSep; continue; } throw new FormatException(); case ParsingStage.DigitOrSep: if (Char.IsDigit(c)) { dv = dv * 10 + ((int)c) - ((int)'0'); i++; haveDigits = true; continue; } if (c == sep) { if (wsCount > 0) { throw new ArgumentOutOfRangeException("input"); } i++; haveSep = true; value = dv * sign; dv = 0; ps = ParsingStage.DigitOrUnit; continue; } isWhiteSpace = Char.IsWhiteSpace(c); if (isWhiteSpace || c == '%' || Char.IsLetter(c)) { if (isWhiteSpace) { if (!haveDigits) { throw new ArgumentOutOfRangeException("input"); } wsCount++; i++; continue; } value = dv * sign; dv = 0; unitStart = i; if (haveSep) { haveDigits = false; ps = ParsingStage.DigitOrUnit; } else { ps = ParsingStage.Unit; } wsCount = 0; continue; } throw new FormatException(); case ParsingStage.DigitOrUnit: if (c == '%') { unitStart = i; unitLen = 1; done = true; continue; } isWhiteSpace = Char.IsWhiteSpace(c); if (isWhiteSpace || Char.IsLetter(c)) { if (isWhiteSpace) { wsCount++; i++; continue; } ps = ParsingStage.Unit; unitStart = i; continue; } if (Char.IsDigit(c)) { if (wsCount > 0) { throw new ArgumentOutOfRangeException(); } dv = dv + (((int)c) - ((int)'0')) * factor; factor = factor * .1; i++; continue; } throw new FormatException(); case ParsingStage.Unit: if (c == '%' || Char.IsLetter(c)) { i++; unitLen++; continue; } if (unitLen == 0 && Char.IsWhiteSpace(c)) { i++; unitStart++; continue; } done = true; break; } } value += dv * sign; if (unitStart >= 0) { int unitTail = unitStart + unitLen; if (unitTail < count) { for (int j = unitTail; j < count; j++) { if (!Char.IsWhiteSpace(input [j])) { throw new ArgumentOutOfRangeException("input"); } } } if (unitLen == 1 && input [unitStart] == '%') { type = UnitType.Percentage; } else { switch (input.Substring(unitStart, unitLen).ToLower(Helpers.InvariantCulture)) { case "in": type = UnitType.Inch; break; case "cm": type = UnitType.Cm; break; case "mm": type = UnitType.Mm; break; case "pt": type = UnitType.Point; break; case "pc": type = UnitType.Pica; break; case "em": type = UnitType.Em; break; case "ex": type = UnitType.Ex; break; case "px": type = UnitType.Pixel; break; default: throw new ArgumentOutOfRangeException("value"); } } } else { type = UnitType.Pixel; } if (haveSep && type == UnitType.Pixel) { throw new FormatException("Pixel units do not allow floating point values"); } valueSet = true; }
/// <summary> /// Parses response/request header /// </summary> /// <param name="s">data to parse, must be long enough to contain at least the start line</param> /// <param name="isResponse"></param> /// <returns>is header parsing finished</returns> /// <exception cref="InvalidHttpHeaderException">Thrown when parsing is unsuccessful</exception> /// <remarks>Max headers size is limited by 512KiB</remarks> public bool Parse(IDataStream s, bool isResponse) { lock (builder) { if (stage == ParsingStage.Finished) { return(true); } if (s.Length <= nextRead) { return(false); } byte[] arr; // max 512KiB int len = (int)Math.Min(s.Length - nextRead, 524288); arr = s.ReadBytes(nextRead, len); var str = ASCIIEncoding.ASCII.GetString(arr); if (stage == ParsingStage.StatusLine) { if (isResponse) { var match = statusLineRegex.Match(str); if (!match.Success && str.Length < s.Length) { throw new InvalidHttpHeaderException(); } builder.IsRequest = false; builder.HttpVersion = match.Groups["Version"].Value; builder.StatusCode = int.Parse(match.Groups["Code"].Value); builder.ReasonPhrase = match.Groups["ReasonPhrase"].Value; nextRead = match.Length; stage = ParsingStage.Headers; str = str.Substring(nextRead); } else { var match = requestLineRegex.Match(str); if (!match.Success && str.Length < s.Length) { throw new InvalidHttpHeaderException(); } var target = match.Groups["Target"].Value; HttpRequestMethod method; if (!Enum.TryParse(match.Groups["Method"].Value, out method)) { throw new InvalidHttpHeaderException(); } builder.IsRequest = true; builder.HttpVersion = match.Groups["Version"].Value; builder.Method = method; builder.RequestTarget = target; nextRead = match.Length; stage = ParsingStage.Headers; str = str.Substring(nextRead); } } if (stage == ParsingStage.Headers) { int read = 0; Match match; while ((match = headerRegex.Match(str, read)).Success) { // Check for end of the string if (str.Length - (match.Length + read) < 2) { nextRead += read; return(false); } var key = match.Groups["Key"].Value; var value = match.Groups["Value"].Value; builder.AddHeader(key, value); read += match.Length; if (str.Substring(read, 2) != "\r\n") { throw new InvalidHttpHeaderException(); } read += 2; } if (str.Length > 0 && read == 0) { throw new InvalidHttpHeaderException(); } str = str.Substring(read); nextRead += read; } if (stage != ParsingStage.Finished && str.Length >= 2 && str.Substring(0, 2) == "\r\n") { stage = ParsingStage.Finished; nextRead += 2; return(true); } return(false); } }