예제 #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);
      }
    }