Ejemplo n.º 1
0
        public static KeyValue ParseKeyValueFile(string path)
        {
            string[] lines = System.IO.File.ReadAllLines("SampleKeyValues/" + path);
            KeyValue kv    = new KeyValue("");

            foreach (string str in lines)
            {
                if (str.StartsWith("{") || str.StartsWith("//"))
                {
                    continue;
                }
                if (str.Contains("}"))
                {
                    kv = kv.Parent ?? kv; //we reached the end of a parent, go up one level
                    continue;
                }

                string key   = null;
                string value = null;
                for (int i = 0; i < str.Length; i++)
                {
                    if (str.ElementAt(i) == '/' && str.ElementAt(i + 1) == '/')
                    {
                        break;
                    }
                    switch (parseState)
                    {
                    case parseEnum.nil:
                        if (str.ElementAt(i) == '"')
                        {
                            parseState = parseEnum.foundFirstKey;
                            key        = "";
                            continue;
                        }
                        break;

                    case parseEnum.foundFirstKey:
                        if (str.ElementAt(i) != '"')
                        {
                            key = key + str.ElementAt(i).ToString();
                        }
                        else
                        {
                            parseState = parseEnum.foundSecondKey;
                            continue;
                        }
                        break;

                    case parseEnum.foundSecondKey:
                        if (str.ElementAt(i) == '"')
                        {
                            parseState = parseEnum.foundFirstValue;
                            value      = "";
                            continue;
                        }
                        break;

                    case parseEnum.foundFirstValue:
                        if (str.ElementAt(i) != '"')
                        {
                            value = value + str.ElementAt(i).ToString();
                        }
                        else
                        {
                            parseState = parseEnum.foundSecondvalue;
                            continue;
                        }
                        break;

                    case parseEnum.foundSecondvalue:
                        //
                        break;
                    }
                }
                parseState = parseEnum.nil;

                if (key == null && value == null)
                {
                    continue;
                }

                if (value == null)
                {
                    if (kv.Key == "")
                    {
                        kv = new KeyValue(key);
                    }
                    else
                    {
                        KeyValue tmpKv = new KeyValue(key);
                        kv.AddChild(tmpKv);
                        kv = tmpKv; //we found a parent, set kv to be the parent we found
                    }
                }
                else
                {
                    KeyValue tmpKv = new KeyValue(key);
                    tmpKv.Value = value;
                    kv.AddChild(tmpKv);
                }
            }

            return(kv);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Grab all of the keyvalues from a string.
        /// </summary>
        /// <param name="contents">The string containing keyvalues</param>
        /// <param name="allowunnamedkeys">Whether or not to allow unnamed blocks (used in bsp entity lump)</param>
        /// <returns>An array containing all root-level KeyValues in the string</returns>
        /// <exception cref="KVLib.KeyValues.KeyValueParsingException">Throws one of these if parsing fails</exception>
        public static KeyValue[] ParseAllKeyValues(string contents, bool allowunnamedkeys = false)
        {
            if (contents == null)
            {
                throw new KeyValueParsingException("Contents string was null!", new ArgumentNullException());
            }
            try
            {
                parseEnum parseState = parseEnum.lookingForKey;
                KeyValue  basekv     = new KeyValue("base"); // file contents are interpreted as children of this keyvalue
                KeyValue  curparent  = basekv;
                for (int i = 0; i < contents.Length; i++)
                {
                    // go until next symbol
                    if (contents[i] == ' ' || contents[i] == '\t' || contents[i] == '\n' || contents[i] == '\r')
                    {
                        continue;
                    }
                    switch (parseState)
                    {
                    case parseEnum.lookingForKey:
                        if (contents[i] == '{')
                        {
                            if (!allowunnamedkeys)
                            {
                                throw new KeyValueParsingException("Hit unnamed key while parsing without unnamed keys enabled.", null);
                            }
                            // This is a special case - some kv files, in particular bsp entity lumps, have unkeyed kvs
                            KeyValue cur = new KeyValue("UNNAMED");
                            curparent.AddChild(cur);
                            curparent  = cur;
                            parseState = parseEnum.lookingForValue;
                        }
                        else if (contents[i] == '"' || contents[i] == '\'')
                        {
                            //quoted key
                            int j = i + 1;
                            if (j >= contents.Length)
                            {
                                throw new KeyValueParsingException("Couldn't find terminating '" + contents[i].ToString() + "' for key started at position " + i.ToString(), null);
                            }
                            while (contents[j] != contents[i])
                            {
                                // handle escaped quotes
                                if (contents[j] == '\\')
                                {
                                    j++;
                                }
                                j++;
                                if (j >= contents.Length)
                                {
                                    throw new KeyValueParsingException("Couldn't find terminating '" + contents[i].ToString() + "' for key started at position " + i.ToString(), null);
                                }
                            }
                            //ok, now contents[i] and contents[j] are the same character, on either end of the key
                            KeyValue cur = new KeyValue(contents.Substring(i + 1, j - (i + 1)));
                            //Console.WriteLine("DEBUG: " + contents.Substring(i + 1, j - (i + 1)));
                            curparent.AddChild(cur);
                            curparent  = cur;
                            parseState = parseEnum.lookingForValue;
                            i          = j;
                        }
                        else if (Char.IsLetter(contents[i]))
                        {
                            //un-quoted key
                            int j = i;
                            while (contents[j] != ' ' && contents[j] != '\t' && contents[j] != '\n' && contents[j] != '\r')
                            {
                                j++;
                                if (j > contents.Length)
                                {
                                    throw new KeyValueParsingException("Couldn't find end of key started at position " + i.ToString(), null);
                                }
                            }
                            KeyValue cur = new KeyValue(contents.Substring(i, j - i));
                            curparent.AddChild(cur);
                            curparent  = cur;
                            parseState = parseEnum.lookingForValue;
                            i          = j;
                        }
                        else if (contents[i] == '}')
                        {
                            //drop one level
                            curparent = curparent.Parent;
                        }
                        else if (contents[i] == '/')
                        {
                            if (i + 1 < contents.Length && contents[i + 1] == '/')
                            {
                                // we're in a comment! throw stuff away until the next \n
                                while (i < contents.Length && contents[i] != '\n')
                                {
                                    i++;
                                }
                            }
                            else
                            {
                                if (BREAK_SPEC)
                                {
                                    // Valve (incorrectly?) matches / as a single-line comment
                                    while (i < contents.Length && contents[i] != '\n')
                                    {
                                        i++;
                                    }
                                }
                            }
                        }
                        else
                        {
                            throw new KeyValueParsingException("Unexpected '" + contents[i].ToString() + "' at position " + i.ToString(), null);
                        }
                        break;

                    case parseEnum.lookingForValue:
                        if (contents[i] == '{')
                        {
                            // it's a list of children
                            // thankfully, we don't actually need to handle this!
                            parseState = parseEnum.lookingForKey;
                        }
                        else if (contents[i] == '"' || contents[i] == '\'')
                        {
                            //quoted value
                            int j = i + 1;
                            while (contents[j] != contents[i])
                            {
                                // handle escaped quotes
                                if (contents[j] == '\\')
                                {
                                    j++;
                                }
                                j++;
                                if (j > contents.Length)
                                {
                                    throw new KeyValueParsingException("Couldn't find terminating '" + contents[i].ToString() + "' for key started at position " + i.ToString(), null);
                                }
                            }
                            //ok, now contents[i] and contents[j] are the same character, on either end of the value
                            curparent.Set(contents.Substring(i + 1, j - (i + 1)));
                            curparent  = curparent.Parent;
                            parseState = parseEnum.lookingForKey;
                            i          = j;
                        }
                        else if (contents[i] == '/')
                        {
                            if (i + 1 < contents.Length && contents[i + 1] == '/')
                            {
                                // we're in a comment! throw stuff away until the next \n
                                while (i < contents.Length && contents[i] != '\n')
                                {
                                    i++;
                                }
                            }
                        }
                        else if (!Char.IsWhiteSpace(contents[i]))
                        {
                            int j = i;
                            while (contents[j] != ' ' && contents[j] != '\t' && contents[j] != '\n' && contents[j] != '\r')
                            {
                                j++;
                                if (j > contents.Length)
                                {
                                    // a value ending the file counts as ending the value
                                    break;
                                }
                            }
                            curparent.Set(contents.Substring(i, j - i));
                            curparent  = curparent.Parent;
                            parseState = parseEnum.lookingForKey;
                            i          = j;
                        }
                        else
                        {
                            throw new KeyValueParsingException("Unexpected '" + contents[i].ToString() + "' at position " + i.ToString(), null);
                        }
                        break;
                    }
                }
                // At the end of the file, we should be looking for another key
                if (parseState != parseEnum.lookingForKey)
                {
                    throw new KeyNotFoundException("File ended while looking for value", null);
                }
                // At the end of the file, all block values should be closed
                if (curparent != basekv)
                {
                    throw new KeyNotFoundException("Unterminated child blocks", null);
                }
                KeyValue[] ret = basekv.Children.ToArray <KeyValue>();
                basekv.ClearChildParents();
                return(ret);
            }
            catch (KeyValueParsingException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                throw new KeyValueParsingException("Hit an exception while parsing kv data!", e);
            }
        }