Ejemplo n.º 1
0
        internal static JArray Parse(CharReader reader)
        {
            // Purpose: Convert a partial string into a JArray
            // Author : Scott Bakker
            // Created: 09/13/2019
            // LastMod: 08/11/2020
            if (reader == null || reader.Peek() == -1)
            {
                return(null);
            }
            JArray result = new JArray();

            JsonRoutines.SkipBOM(reader);
            JsonRoutines.SkipWhitespace(reader);
            if (reader.Peek() != '[')
            {
                throw new SystemException(
                          $"JSON Error: Unexpected token to start JArray: {reader.Peek()}");
            }
            reader.Read();
            do
            {
                JsonRoutines.SkipWhitespace(reader);
                // check for symbols
                if (reader.Peek() == ']')
                {
                    reader.Read();
                    break; // done building JArray
                }
                if (reader.Peek() == ',')
                {
                    // this logic ignores extra commas, but is ok
                    reader.Read();
                    continue;             // next value
                }
                if (reader.Peek() == '{') // JObject
                {
                    JObject jo = JObject.Parse(reader);
                    result.Add(jo);
                    continue;
                }
                if (reader.Peek() == '[') // JArray
                {
                    JArray ja = JArray.Parse(reader);
                    result.Add(ja);
                    continue;
                }
                // Get value as a string, convert to object
                string tempValue = JsonRoutines.GetToken(reader);
                result.Add(JsonRoutines.JsonValueToObject(tempValue));
            } while (true);
            return(result);
        }
Ejemplo n.º 2
0
 internal static void SkipBOM(CharReader reader)
 {
     // Purpose: Skip over Byte-Order Mark (BOM) at the beginning of a stream
     // Author : Scott Bakker
     // Created: 05/20/2020
     // LastMod: 08/11/2020
     // UTF-8 BOM = 0xEF,0xBB,0xBF = 239,187,191
     if (reader.Peek() == '\xEF' && reader.PeekNext() == '\xBB')
     {
         reader.Read();
         reader.Read();
         if (reader.Peek() != '\xBF')
         {
             throw new SystemException($"JSON Error: Invalid BOM character: 0x{reader.Peek():X2}");
         }
         reader.Read();
     }
 }
Ejemplo n.º 3
0
        internal static JObject Parse(CharReader reader)
        {
            // Purpose: Convert a partial string into a JObject
            // Author : Scott Bakker
            // Created: 09/13/2019
            // LastMod: 08/11/2020
            if (reader == null || reader.Peek() == -1)
            {
                return(null);
            }
            JObject result = new JObject();

            JsonRoutines.SkipBOM(reader);
            JsonRoutines.SkipWhitespace(reader);
            if (reader.Peek() != '{')
            {
                throw new SystemException(
                          $"JSON Error: Unexpected token to start JObject: {reader.Peek()}");
            }
            reader.Read();
            do
            {
                JsonRoutines.SkipWhitespace(reader);
                // check for symbols
                if (reader.Peek() == '}')
                {
                    reader.Read();
                    break; // done building JObject
                }
                if (reader.Peek() == ',')
                {
                    // this logic ignores extra commas, but is ok
                    reader.Read();
                    continue; // Next key/value
                }
                string tempKey = JsonRoutines.GetToken(reader);
                if (JsonRoutines.IsWhitespaceString(tempKey))
                {
                    throw new SystemException(JsonKeyError);
                }
                if (tempKey.Length <= 2 || !tempKey.StartsWith("\"") || !tempKey.EndsWith("\""))
                {
                    throw new SystemException($"JSON Error: Invalid key format: {tempKey}");
                }
                // Convert to usable key
                tempKey = JsonRoutines.JsonValueToObject(tempKey).ToString();
                if (JsonRoutines.IsWhitespaceString(tempKey.Substring(1, tempKey.Length - 2)))
                {
                    throw new SystemException(JsonKeyError);
                }
                // Check for ":" between key and value
                JsonRoutines.SkipWhitespace(reader);
                if (JsonRoutines.GetToken(reader) != ":")
                {
                    throw new SystemException($"JSON Error: Missing colon: {tempKey}");
                }
                // Get value
                JsonRoutines.SkipWhitespace(reader);
                if (reader.Peek() == '{') // JObject
                {
                    JObject jo = JObject.Parse(reader);
                    result[tempKey] = jo;
                    continue;
                }
                if (reader.Peek() == '[') // JArray
                {
                    JArray ja = JArray.Parse(reader);
                    result[tempKey] = ja;
                    continue;
                }
                // Get value as a string, convert to object
                string tempValue = JsonRoutines.GetToken(reader);
                result[tempKey] = JsonRoutines.JsonValueToObject(tempValue);
            } while (true);
            return(result);
        }
Ejemplo n.º 4
0
        internal static void SkipWhitespace(CharReader reader)
        {
            // Purpose: Skip over any whitespace characters or any recognized comments
            // Author : Scott Bakker
            // Created: 09/23/2019
            // LastMod: 08/11/2020
            // Notes  : Comments consist of "/*...*/" or "//" to eol (aka line comment).
            //        : "//" comments don't need an eol if at the end, but "/*" does need "*/".
            if (reader == null)
            {
                return;
            }
            bool inComment     = false;
            bool inLineComment = false;

            while (reader.Peek() != -1)
            {
                if (inComment)
                {
                    if (reader.Peek() == '*' && reader.PeekNext() == '/') // found ending "*/"
                    {
                        inComment = false;
                        reader.Read();
                    }
                    reader.Read();
                    continue;
                }
                if (inLineComment)
                {
                    if (reader.Peek() == '\r' || reader.Peek() == '\n') // found end of line
                    {
                        inLineComment = false;
                    }
                    reader.Read();
                    continue;
                }
                if (reader.Peek() == '/' && reader.PeekNext() == '*')
                {
                    inComment = true;
                    reader.Read();
                    reader.Read();
                    continue;
                }
                if (reader.Peek() == '/' && reader.PeekNext() == '/')
                {
                    inLineComment = true;
                    reader.Read();
                    reader.Read();
                    continue;
                }
                if (IsWhitespace((char)reader.Peek()))
                {
                    reader.Read();
                    continue;
                }
                break;
            }
            if (inComment)
            {
                throw new SystemException("JSON Error: Comment starting with /* is not terminated by */");
            }
        }
Ejemplo n.º 5
0
        internal static string GetToken(CharReader reader)
        {
            // Purpose: Get a single token from string value for parsing
            // Author : Scott Bakker
            // Created: 09/13/2019
            // LastMod: 03/09/2021
            // Notes  : Does not do escaped character expansion here, just passes exact value.
            //        : Properly handles \" within strings this way, but nothing else.
            if (reader == null || reader.Peek() == -1)
            {
                return(null);
            }
            char c;

            // Ignore whitespace before token
            SkipWhitespace(reader);
            // Stop if one-character JSON symbol found
            if (IsJsonSymbol((char)reader.Peek()))
            {
                return(((char)reader.Read()).ToString());
            }
            // Have to build token char by char
            StringBuilder result        = new();
            bool          inQuote       = false;
            bool          lastBackslash = false;

            do
            {
                // Peek char for this loop
                c = (char)reader.Peek();
                // Check for whitespace or symbols to end token
                if (!inQuote)
                {
                    if (IsWhitespace(c))
                    {
                        reader.Read(); // gobble char
                        break;         // end token
                    }
                    if (IsJsonSymbol(c))
                    {
                        // don't gobble char
                        break; // end token
                    }
                    // Any comments end the token
                    if (c == '/')
                    {
                        if (reader.PeekNext() == '*' || reader.PeekNext() == '/')
                        {
                            // don't gobble char
                            break; // end token
                        }
                    }
                    if (c != '\"' && !IsJsonValueChar(c))
                    {
                        throw new SystemException($"JSON Error: Unexpected character: {c}");
                    }
                }
                // Check for escaped chars
                if (inQuote && lastBackslash)
                {
                    // Add backslash and character, no expansion here
                    result.Append('\\');
                    result.Append((char)reader.Read());
                    lastBackslash = false;
                }
                else if (inQuote && c == '\\')
                {
                    // Remember backslash for next loop, but don't add it to result
                    lastBackslash = true;
                }
                else if (c == '\"')
                {
                    // Check for quotes around a string
                    if (inQuote)
                    {
                        result.Append((char)reader.Read()); // add ending quote
                        inQuote = false;
                        break;                              // Token is done
                    }
                    if (result.Length > 0)
                    {
                        // Quote in the middle of a token?
                        throw new SystemException("JSON Error: Unexpected quote char");
                    }
                    result.Append((char)reader.Read()); // add beginning quote
                    inQuote = true;
                }
                else
                {
                    // Add this char
                    result.Append((char)reader.Read());
                }
            }while (reader.Peek() != -1);
            return(result.ToString());
        }