예제 #1
0
		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));
				}
			}
		}
예제 #2
0
		private void ClearRecentString()
		{
			if (_buffer != null)
				_buffer.Position = 0;

			_stringReference = new StringReference();
		}
예제 #3
0
		private void ReadStringIntoBuffer(char quote)
		{
			int charPos = _charPos;
			int initialPosition = _charPos;
			int lastWritePosition = _charPos;
			StringBuffer buffer = null;

			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))
						{
							_charPos = charPos;
							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];

						char writeChar;

						switch (currentChar)
						{
							case 'b':
								charPos++;
								writeChar = '\b';
								break;
							case 't':
								charPos++;
								writeChar = '\t';
								break;
							case 'n':
								charPos++;
								writeChar = '\n';
								break;
							case 'f':
								charPos++;
								writeChar = '\f';
								break;
							case 'r':
								charPos++;
								writeChar = '\r';
								break;
							case '\\':
								charPos++;
								writeChar = '\\';
								break;
							case '"':
							case '\'':
							case '/':
								writeChar = currentChar;
								charPos++;
								break;
							case 'u':
								charPos++;
								_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;
											}

											if (buffer == null)
												buffer = GetBuffer();

											WriteCharToBuffer(buffer, 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 = charPos;
								throw JsonReaderException.Create(this, "Bad JSON escape sequence: {0}.".FormatWith(CultureInfo.InvariantCulture, @"\" + currentChar));
						}

						if (buffer == null)
							buffer = GetBuffer();

						WriteCharToBuffer(buffer, 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
							{
								if (buffer == null)
									buffer = GetBuffer();

								if (charPos > lastWritePosition)
									buffer.Append(_chars, lastWritePosition, charPos - lastWritePosition);

								_stringReference = new StringReference(buffer.GetInternalBuffer(), 0, buffer.Position);
							}

							charPos++;
							_charPos = charPos;
							return;
						}
						break;
				}
			}
		}
예제 #4
0
		private void ParseComment()
		{
			// should have already parsed / character before reaching this method
			_charPos++;

			if (!EnsureChars(1, false) || _chars[_charPos] != '*')
				throw JsonReaderException.Create(this, "Error parsing comment. Expected: *, got {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
			else
				_charPos++;

			int initialPosition = _charPos;

			bool commentFinished = false;

			while (!commentFinished)
			{
				switch (_chars[_charPos])
				{
					case '\0':
						if (_charsUsed == _charPos)
						{
							if (ReadData(true) == 0)
								throw JsonReaderException.Create(this, "Unexpected end while parsing comment.");
						}
						else
						{
							_charPos++;
						}
						break;
					case '*':
						_charPos++;

						if (EnsureChars(0, true))
						{
							if (_chars[_charPos] == '/')
							{
								_stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition - 1);

								_charPos++;
								commentFinished = true;
							}
						}
						break;
					case StringUtils.CarriageReturn:
						ProcessCarriageReturn(true);
						break;
					case StringUtils.LineFeed:
						ProcessLineFeed();
						break;
					default:
						_charPos++;
						break;
				}
			}

			SetToken(JsonToken.Comment, _stringReference.ToString());

			ClearRecentString();
		}
예제 #5
0
		private void ParseNumber()
		{
			ShiftBufferIfNeeded();

			char firstChar = _chars[_charPos];
			int initialPosition = _charPos;

			ReadNumberIntoBuffer();

			_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();

					// decimal.Parse doesn't support parsing hexadecimal values
					int integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt32(number, 16) : Convert.ToInt32(number, 8);

					numberValue = integer;
				}
				else
				{
					numberValue = ConvertUtils.Int32Parse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length);
				}

				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();

					// 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);
				}
				else
				{
					string number = _stringReference.ToString();

					numberValue = decimal.Parse(number, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture);
				}

				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();

					numberValue = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8);
					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.Invalid)
					{
						string number = _stringReference.ToString();

						if (_floatParseHandling == FloatParseHandling.Decimal)
							numberValue = decimal.Parse(number, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture);
						else
							numberValue = Convert.ToDouble(number, CultureInfo.InvariantCulture);

						numberType = JsonToken.Float;
					}
					else if (parseResult == ParseResult.Overflow)
					{
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE40 || PORTABLE)
						string number = _stringReference.ToString();
						numberValue = BigInteger.Parse(number, CultureInfo.InvariantCulture);
						numberType = JsonToken.Integer;
#else
	// todo - validate number was a valid integer to make sure overflow was the reason for failure
            throw JsonReaderException.Create(this, "JSON integer {0} is too large or small for an Int64.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
#endif
					}
					else
					{
						throw JsonReaderException.Create(this, "Unknown error parsing integer.");
					}
				}
			}

			ClearRecentString();

			SetToken(numberType, numberValue);
		}
예제 #6
0
		private void ParseConstructor()
		{
			if (MatchValueWithTrailingSeperator("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.");
			}
		}