internal static bool TryParseDateTimeOffsetIso(StringReference text, out DateTimeOffset dt) { DateTimeParser dateTimeParser = new DateTimeParser(); if (!dateTimeParser.Parse(text.Chars, text.StartIndex, text.Length)) { dt = default(DateTimeOffset); return(false); } DateTime d = CreateDateTime(dateTimeParser); TimeSpan offset; switch (dateTimeParser.Zone) { case ParserTimeZone.Utc: offset = new TimeSpan(0L); break; case ParserTimeZone.LocalWestOfUtc: offset = new TimeSpan(-dateTimeParser.ZoneHour, -dateTimeParser.ZoneMinute, 0); break; case ParserTimeZone.LocalEastOfUtc: offset = new TimeSpan(dateTimeParser.ZoneHour, dateTimeParser.ZoneMinute, 0); break; default: offset = TimeZoneInfo.Local.GetUtcOffset(d); break; } long ticks = d.Ticks - offset.Ticks; if (ticks < 0 || ticks > 3155378975999999999) { dt = default(DateTimeOffset); return(false); } dt = new DateTimeOffset(d, offset); return(true); }
public static bool StartsWith(this StringReference s, string text) { if (text.Length > s.Length) { return(false); } char[] chars = s.Chars; for (int i = 0; i < text.Length; i++) { if (text[i] != chars[i + s.StartIndex]) { return(false); } } return(true); }
private static bool TryParseDateTimeMicrosoft(StringReference text, DateTimeZoneHandling dateTimeZoneHandling, out DateTime dt) { long ticks; TimeSpan offset; DateTimeKind kind; if (!TryParseMicrosoftDate(text, out ticks, out offset, out kind)) { dt = default(DateTime); return false; } DateTime utcDateTime = ConvertJavaScriptTicksToDateTime(ticks); switch (kind) { case DateTimeKind.Unspecified: dt = DateTime.SpecifyKind(utcDateTime.ToLocalTime(), DateTimeKind.Unspecified); break; case DateTimeKind.Local: dt = utcDateTime.ToLocalTime(); break; default: dt = utcDateTime; break; } dt = EnsureDateTime(dt, dateTimeZoneHandling); return true; }
private static bool TryParseMicrosoftDate(StringReference text, out long ticks, out TimeSpan offset, out DateTimeKind kind) { kind = DateTimeKind.Utc; int index = text.IndexOf('+', 7, text.Length - 8); if (index == -1) { index = text.IndexOf('-', 7, text.Length - 8); } if (index != -1) { kind = DateTimeKind.Local; if (!TryReadOffset(text, index + text.StartIndex, out offset)) { ticks = 0; return false; } } else { offset = TimeSpan.Zero; index = text.Length - 2; } return (ConvertUtils.Int64TryParse(text.Chars, 6 + text.StartIndex, index - 6, out ticks) == ParseResult.Success); }
internal static bool TryParseDateTimeOffset(StringReference s, string dateFormatString, CultureInfo culture, out DateTimeOffset dt) { if (s.Length > 0) { int i = s.StartIndex; if (s[i] == '/') { if (s.Length >= 9 && s.StartsWith("/Date(") && s.EndsWith(")/")) { if (TryParseDateTimeOffsetMicrosoft(s, out dt)) { return true; } } } else if (s.Length >= 19 && s.Length <= 40 && char.IsDigit(s[i]) && s[i + 10] == 'T') { if (TryParseDateTimeOffsetIso(s, out dt)) { return true; } } if (!string.IsNullOrEmpty(dateFormatString)) { if (TryParseDateTimeOffsetExact(s.ToString(), dateFormatString, culture, out dt)) { return true; } } } dt = default(DateTimeOffset); return false; }
internal static bool TryParseDateTimeOffsetIso(StringReference text, out DateTimeOffset dt) { DateTimeParser dateTimeParser = new DateTimeParser(); if (!dateTimeParser.Parse(text.Chars, text.StartIndex, text.Length)) { dt = default(DateTimeOffset); return false; } DateTime d = CreateDateTime(dateTimeParser); TimeSpan offset; switch (dateTimeParser.Zone) { case ParserTimeZone.Utc: offset = new TimeSpan(0L); break; case ParserTimeZone.LocalWestOfUtc: offset = new TimeSpan(-dateTimeParser.ZoneHour, -dateTimeParser.ZoneMinute, 0); break; case ParserTimeZone.LocalEastOfUtc: offset = new TimeSpan(dateTimeParser.ZoneHour, dateTimeParser.ZoneMinute, 0); break; default: offset = TimeZoneInfo.Local.GetUtcOffset(d); break; } long ticks = d.Ticks - offset.Ticks; if (ticks < 0 || ticks > 3155378975999999999) { dt = default(DateTimeOffset); return false; } dt = new DateTimeOffset(d, offset); return true; }
internal static bool TryParseDateTimeIso(StringReference text, DateTimeZoneHandling dateTimeZoneHandling, out DateTime dt) { DateTimeParser dateTimeParser = new DateTimeParser(); if (!dateTimeParser.Parse(text.Chars, text.StartIndex, text.Length)) { dt = default(DateTime); return false; } DateTime d = CreateDateTime(dateTimeParser); long ticks; switch (dateTimeParser.Zone) { case ParserTimeZone.Utc: d = new DateTime(d.Ticks, DateTimeKind.Utc); break; case ParserTimeZone.LocalWestOfUtc: { TimeSpan offset = new TimeSpan(dateTimeParser.ZoneHour, dateTimeParser.ZoneMinute, 0); ticks = d.Ticks + offset.Ticks; if (ticks <= DateTime.MaxValue.Ticks) { d = new DateTime(ticks, DateTimeKind.Utc).ToLocalTime(); } else { ticks += d.GetUtcOffset().Ticks; if (ticks > DateTime.MaxValue.Ticks) { ticks = DateTime.MaxValue.Ticks; } d = new DateTime(ticks, DateTimeKind.Local); } break; } case ParserTimeZone.LocalEastOfUtc: { TimeSpan offset = new TimeSpan(dateTimeParser.ZoneHour, dateTimeParser.ZoneMinute, 0); ticks = d.Ticks - offset.Ticks; if (ticks >= DateTime.MinValue.Ticks) { d = new DateTime(ticks, DateTimeKind.Utc).ToLocalTime(); } else { ticks += d.GetUtcOffset().Ticks; if (ticks < DateTime.MinValue.Ticks) { ticks = DateTime.MinValue.Ticks; } d = new DateTime(ticks, DateTimeKind.Local); } break; } } dt = EnsureDateTime(d, dateTimeZoneHandling); return true; }
private void ParseConstructor() { if (MatchValueWithTrailingSeparator("new")) { EatWhitespace(false); int initialPosition = _charPos; int endPosition; while (true) { char currentChar = _chars[_charPos]; if (currentChar == '\0') { if (_charsUsed == _charPos) { if (ReadData(true) == 0) { throw JsonReaderException.Create(this, "Unexpected end while parsing constructor."); } } else { endPosition = _charPos; _charPos++; break; } } else if (char.IsLetterOrDigit(currentChar)) { _charPos++; } else if (currentChar == StringUtils.CarriageReturn) { endPosition = _charPos; ProcessCarriageReturn(true); break; } else if (currentChar == StringUtils.LineFeed) { endPosition = _charPos; ProcessLineFeed(); break; } else if (char.IsWhiteSpace(currentChar)) { endPosition = _charPos; _charPos++; break; } else if (currentChar == '(') { endPosition = _charPos; break; } else { throw JsonReaderException.Create(this, "Unexpected character while parsing constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar)); } } _stringReference = new StringReference(_chars, initialPosition, endPosition - initialPosition); string constructorName = _stringReference.ToString(); EatWhitespace(false); if (_chars[_charPos] != '(') { throw JsonReaderException.Create(this, "Unexpected character while parsing constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); } _charPos++; ClearRecentString(); SetToken(JsonToken.StartConstructor, constructorName); } else { throw JsonReaderException.Create(this, "Unexpected content while parsing JSON."); } }
private void ClearRecentString() { _stringBuffer.Position = 0; _stringReference = new StringReference(); }
private void ParseUnquotedProperty() { int initialPosition = _charPos; // parse unquoted property name until whitespace or colon while (true) { switch (_chars[_charPos]) { case '\0': if (_charsUsed == _charPos) { if (ReadData(true) == 0) { throw JsonReaderException.Create(this, "Unexpected end while parsing unquoted property name."); } break; } _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); return; default: char currentChar = _chars[_charPos]; if (ValidIdentifierChar(currentChar)) { _charPos++; break; } else if (char.IsWhiteSpace(currentChar) || currentChar == ':') { _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); return; } throw JsonReaderException.Create(this, "Invalid JavaScript property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar)); } } }
private void ReadStringIntoBuffer(char quote) { int charPos = _charPos; int initialPosition = _charPos; int lastWritePosition = _charPos; _stringBuffer.Position = 0; while (true) { switch (_chars[charPos++]) { case '\0': if (_charsUsed == charPos - 1) { charPos--; if (ReadData(true) == 0) { _charPos = charPos; throw JsonReaderException.Create(this, "Unterminated string. Expected delimiter: {0}.".FormatWith(CultureInfo.InvariantCulture, quote)); } } break; case '\\': _charPos = charPos; if (!EnsureChars(0, true)) { throw JsonReaderException.Create(this, "Unterminated string. Expected delimiter: {0}.".FormatWith(CultureInfo.InvariantCulture, quote)); } // start of escape sequence int escapeStartPos = charPos - 1; char currentChar = _chars[charPos]; charPos++; char writeChar; switch (currentChar) { case 'b': writeChar = '\b'; break; case 't': writeChar = '\t'; break; case 'n': writeChar = '\n'; break; case 'f': writeChar = '\f'; break; case 'r': writeChar = '\r'; break; case '\\': writeChar = '\\'; break; case '"': case '\'': case '/': writeChar = currentChar; break; case 'u': _charPos = charPos; writeChar = ParseUnicode(); if (StringUtils.IsLowSurrogate(writeChar)) { // low surrogate with no preceding high surrogate; this char is replaced writeChar = UnicodeReplacementChar; } else if (StringUtils.IsHighSurrogate(writeChar)) { bool anotherHighSurrogate; // loop for handling situations where there are multiple consecutive high surrogates do { anotherHighSurrogate = false; // potential start of a surrogate pair if (EnsureChars(2, true) && _chars[_charPos] == '\\' && _chars[_charPos + 1] == 'u') { char highSurrogate = writeChar; _charPos += 2; writeChar = ParseUnicode(); if (StringUtils.IsLowSurrogate(writeChar)) { // a valid surrogate pair! } else if (StringUtils.IsHighSurrogate(writeChar)) { // another high surrogate; replace current and start check over highSurrogate = UnicodeReplacementChar; anotherHighSurrogate = true; } else { // high surrogate not followed by low surrogate; original char is replaced highSurrogate = UnicodeReplacementChar; } EnsureBufferNotEmpty(); WriteCharToBuffer(highSurrogate, lastWritePosition, escapeStartPos); lastWritePosition = _charPos; } else { // there are not enough remaining chars for the low surrogate or is not follow by unicode sequence // replace high surrogate and continue on as usual writeChar = UnicodeReplacementChar; } } while (anotherHighSurrogate); } charPos = _charPos; break; default: _charPos = charPos; throw JsonReaderException.Create(this, "Bad JSON escape sequence: {0}.".FormatWith(CultureInfo.InvariantCulture, @"\" + currentChar)); } EnsureBufferNotEmpty(); WriteCharToBuffer(writeChar, lastWritePosition, escapeStartPos); lastWritePosition = charPos; break; case StringUtils.CarriageReturn: _charPos = charPos - 1; ProcessCarriageReturn(true); charPos = _charPos; break; case StringUtils.LineFeed: _charPos = charPos - 1; ProcessLineFeed(); charPos = _charPos; break; case '"': case '\'': if (_chars[charPos - 1] == quote) { charPos--; if (initialPosition == lastWritePosition) { _stringReference = new StringReference(_chars, initialPosition, charPos - initialPosition); } else { EnsureBufferNotEmpty(); if (charPos > lastWritePosition) { _stringBuffer.Append(_arrayPool, _chars, lastWritePosition, charPos - lastWritePosition); } _stringReference = new StringReference(_stringBuffer.InternalBuffer, 0, _stringBuffer.Position); } charPos++; _charPos = charPos; return; } break; } } }
private void ClearRecentString() { if (_buffer != null) _buffer.Position = 0; _stringReference = new StringReference(); }
private void ParseComment() { // should have already parsed / character before reaching this method _charPos++; if (!EnsureChars(1, false)) throw JsonReaderException.Create(this, "Unexpected end while parsing comment."); bool singlelineComment; if (_chars[_charPos] == '*') singlelineComment = false; else if (_chars[_charPos] == '/') singlelineComment = true; else throw JsonReaderException.Create(this, "Error parsing comment. Expected: *, got {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); _charPos++; int initialPosition = _charPos; bool commentFinished = false; while (!commentFinished) { switch (_chars[_charPos]) { case '\0': if (_charsUsed == _charPos) { if (ReadData(true) == 0) { if (!singlelineComment) throw JsonReaderException.Create(this, "Unexpected end while parsing comment."); _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); commentFinished = true; } } else { _charPos++; } break; case '*': _charPos++; if (!singlelineComment) { if (EnsureChars(0, true)) { if (_chars[_charPos] == '/') { _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition - 1); _charPos++; commentFinished = true; } } } break; case StringUtils.CarriageReturn: if (singlelineComment) { _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); commentFinished = true; } ProcessCarriageReturn(true); break; case StringUtils.LineFeed: if (singlelineComment) { _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); commentFinished = true; } ProcessLineFeed(); break; default: _charPos++; break; } } SetToken(JsonToken.Comment, _stringReference.ToString()); ClearRecentString(); }
private static bool TryParseDateTimeOffsetMicrosoft(StringReference text, out DateTimeOffset dt) { long ticks; TimeSpan offset; DateTimeKind kind; if (!TryParseMicrosoftDate(text, out ticks, out offset, out kind)) { dt = default(DateTime); return false; } DateTime utcDateTime = ConvertJavaScriptTicksToDateTime(ticks); dt = new DateTimeOffset(utcDateTime.Add(offset).Ticks, offset); return true; }
private void ParseNumber(ReadType readType) { ShiftBufferIfNeeded(); char firstChar = _chars[_charPos]; int initialPosition = _charPos; ReadNumberIntoBuffer(); // set state to PostValue now so that if there is an error parsing the number then the reader can continue SetPostValueState(true); _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); object numberValue; JsonToken numberType; bool singleDigit = (char.IsDigit(firstChar) && _stringReference.Length == 1); bool nonBase10 = (firstChar == '0' && _stringReference.Length > 1 && _stringReference.Chars[_stringReference.StartIndex + 1] != '.' && _stringReference.Chars[_stringReference.StartIndex + 1] != 'e' && _stringReference.Chars[_stringReference.StartIndex + 1] != 'E'); if (readType == ReadType.ReadAsInt32) { if (singleDigit) { // digit char values start at 48 numberValue = firstChar - 48; } else if (nonBase10) { string number = _stringReference.ToString(); try { int integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt32(number, 16) : Convert.ToInt32(number, 8); numberValue = integer; } catch (Exception ex) { throw JsonReaderException.Create(this, "Input string '{0}' is not a valid integer.".FormatWith(CultureInfo.InvariantCulture, number), ex); } } else { int value; ParseResult parseResult = ConvertUtils.Int32TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out value); if (parseResult == ParseResult.Success) { numberValue = value; } else if (parseResult == ParseResult.Overflow) { throw JsonReaderException.Create(this, "JSON integer {0} is too large or small for an Int32.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString())); } else { throw JsonReaderException.Create(this, "Input string '{0}' is not a valid integer.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString())); } } numberType = JsonToken.Integer; } else if (readType == ReadType.ReadAsDecimal) { if (singleDigit) { // digit char values start at 48 numberValue = (decimal)firstChar - 48; } else if (nonBase10) { string number = _stringReference.ToString(); try { // decimal.Parse doesn't support parsing hexadecimal values long integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8); numberValue = Convert.ToDecimal(integer); } catch (Exception ex) { throw JsonReaderException.Create(this, "Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture, number), ex); } } else { string number = _stringReference.ToString(); decimal value; if (decimal.TryParse(number, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out value)) { numberValue = value; } else { throw JsonReaderException.Create(this, "Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString())); } } numberType = JsonToken.Float; } else if (readType == ReadType.ReadAsDouble) { if (singleDigit) { // digit char values start at 48 numberValue = (double)firstChar - 48; } else if (nonBase10) { string number = _stringReference.ToString(); try { // double.Parse doesn't support parsing hexadecimal values long integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8); numberValue = Convert.ToDouble(integer); } catch (Exception ex) { throw JsonReaderException.Create(this, "Input string '{0}' is not a valid double.".FormatWith(CultureInfo.InvariantCulture, number), ex); } } else { string number = _stringReference.ToString(); double value; if (double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out value)) { numberValue = value; } else { throw JsonReaderException.Create(this, "Input string '{0}' is not a valid double.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString())); } } numberType = JsonToken.Float; } else { if (singleDigit) { // digit char values start at 48 numberValue = (long)firstChar - 48; numberType = JsonToken.Integer; } else if (nonBase10) { string number = _stringReference.ToString(); try { numberValue = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8); } catch (Exception ex) { throw JsonReaderException.Create(this, "Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, number), ex); } numberType = JsonToken.Integer; } else { long value; ParseResult parseResult = ConvertUtils.Int64TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out value); if (parseResult == ParseResult.Success) { numberValue = value; numberType = JsonToken.Integer; } else if (parseResult == ParseResult.Overflow) { #if !(NET20 || NET35 || PORTABLE40 || PORTABLE) string number = _stringReference.ToString(); if (number.Length > MaximumJavascriptIntegerCharacterLength) { throw JsonReaderException.Create(this, "JSON integer {0} is too large to parse.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString())); } numberValue = BigIntegerParse(number, CultureInfo.InvariantCulture); numberType = JsonToken.Integer; #else throw JsonReaderException.Create(this, "JSON integer {0} is too large or small for an Int64.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString())); #endif } else { string number = _stringReference.ToString(); if (_floatParseHandling == FloatParseHandling.Decimal) { decimal d; if (decimal.TryParse(number, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out d)) { numberValue = d; } else { throw JsonReaderException.Create(this, "Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture, number)); } } else { double d; if (double.TryParse(number, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out d)) { numberValue = d; } else { throw JsonReaderException.Create(this, "Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, number)); } } numberType = JsonToken.Float; } } } ClearRecentString(); // index has already been updated SetToken(numberType, numberValue, false); }
private static bool TryReadOffset(StringReference offsetText, int startIndex, out TimeSpan offset) { bool negative = (offsetText[startIndex] == '-'); int hours; if (ConvertUtils.Int32TryParse(offsetText.Chars, startIndex + 1, 2, out hours) != ParseResult.Success) { offset = default(TimeSpan); return false; } int minutes = 0; if (offsetText.Length - startIndex > 5) { if (ConvertUtils.Int32TryParse(offsetText.Chars, startIndex + 3, 2, out minutes) != ParseResult.Success) { offset = default(TimeSpan); return false; } } offset = TimeSpan.FromHours(hours) + TimeSpan.FromMinutes(minutes); if (negative) { offset = offset.Negate(); } return true; }
internal static bool TryParseDateTimeIso(StringReference text, DateTimeZoneHandling dateTimeZoneHandling, out DateTime dt) { DateTimeParser dateTimeParser = new DateTimeParser(); if (!dateTimeParser.Parse(text.Chars, text.StartIndex, text.Length)) { dt = default(DateTime); return(false); } DateTime d = CreateDateTime(dateTimeParser); long ticks; switch (dateTimeParser.Zone) { case ParserTimeZone.Utc: d = new DateTime(d.Ticks, DateTimeKind.Utc); break; case ParserTimeZone.LocalWestOfUtc: { TimeSpan offset = new TimeSpan(dateTimeParser.ZoneHour, dateTimeParser.ZoneMinute, 0); ticks = d.Ticks + offset.Ticks; if (ticks <= DateTime.MaxValue.Ticks) { d = new DateTime(ticks, DateTimeKind.Utc).ToLocalTime(); } else { ticks += d.GetUtcOffset().Ticks; if (ticks > DateTime.MaxValue.Ticks) { ticks = DateTime.MaxValue.Ticks; } d = new DateTime(ticks, DateTimeKind.Local); } break; } case ParserTimeZone.LocalEastOfUtc: { TimeSpan offset = new TimeSpan(dateTimeParser.ZoneHour, dateTimeParser.ZoneMinute, 0); ticks = d.Ticks - offset.Ticks; if (ticks >= DateTime.MinValue.Ticks) { d = new DateTime(ticks, DateTimeKind.Utc).ToLocalTime(); } else { ticks += d.GetUtcOffset().Ticks; if (ticks < DateTime.MinValue.Ticks) { ticks = DateTime.MinValue.Ticks; } d = new DateTime(ticks, DateTimeKind.Local); } break; } } dt = EnsureDateTime(d, dateTimeZoneHandling); return(true); }