// This parses the given decorate stream
        // Returns false on errors
        public override bool Parse(TextResourceData data, bool clearerrors)
        {
            //mxd. Already parsed?
            if (!base.AddTextResource(data))
            {
                if (clearerrors)
                {
                    ClearError();
                }
                return(true);
            }

            // Cannot process?
            if (!base.Parse(data, clearerrors))
            {
                return(false);
            }

            // [ZZ] For whatever reason, the parser is closely tied to the tokenizer, and to the general scripting lumps framework (see scripttype).
            //      For this reason I have to still inherit the old tokenizer while only using the new one.
            //ReportError("found zscript? :)");
            prevstreamposition = -1;
            tokenizer          = new ZScriptTokenizer(datareader);

            // region-as-category, ZScript ver
            List <DecorateCategoryInfo> regions = new List <DecorateCategoryInfo>();

            while (true)
            {
                ZScriptToken token = tokenizer.ExpectToken(ZScriptTokenType.Identifier, // const, enum, class, etc
                                                           ZScriptTokenType.Whitespace,
                                                           ZScriptTokenType.Newline,
                                                           ZScriptTokenType.BlockComment, ZScriptTokenType.LineComment,
                                                           ZScriptTokenType.Preprocessor);

                if (token == null) // EOF reached, whatever.
                {
                    break;
                }

                if (!token.IsValid)
                {
                    ReportError("Expected preprocessor statement, const, enum or class declaraction, got " + token);
                    return(false);
                }

                // toplevel tokens allowed are only Preprocessor and Identifier.
                switch (token.Type)
                {
                case ZScriptTokenType.Whitespace:
                case ZScriptTokenType.Newline:
                case ZScriptTokenType.BlockComment:
                    break;

                case ZScriptTokenType.LineComment:
                {
                    string cmtval = token.Value.TrimStart();
                    if (cmtval.Length <= 0 || cmtval[0] != '$')
                    {
                        break;
                    }
                    // check for $GZDB_SKIP
                    if (cmtval.Trim().ToLowerInvariant() == "$gzdb_skip")
                    {
                        return(true);
                    }
                    // if we are in a region, read property using function from ZScriptActorStructure
                    if (regions.Count > 0)
                    {
                        ZScriptActorStructure.ParseGZDBComment(regions.Last().Properties, cmtval);
                    }
                }
                break;

                case ZScriptTokenType.Preprocessor:
                {
                    tokenizer.SkipWhitespace();
                    ZScriptToken directive = tokenizer.ExpectToken(ZScriptTokenType.Identifier);
                    if (directive == null || !directive.IsValid)
                    {
                        ReportError("Expected preprocessor directive, got " + ((Object)directive ?? "<null>").ToString());
                        return(false);
                    }

                    string d_value = directive.Value.ToLowerInvariant();
                    if (d_value == "include")
                    {
                        tokenizer.SkipWhitespace();
                        ZScriptToken include_name = tokenizer.ExpectToken(ZScriptTokenType.Identifier, ZScriptTokenType.String, ZScriptTokenType.Name);
                        if (include_name == null || !include_name.IsValid)
                        {
                            ReportError("Cannot include: expected a string value, got " + ((Object)include_name ?? "<null>").ToString());
                            return(false);
                        }

                        if (!ParseInclude(include_name.Value))
                        {
                            return(false);
                        }
                    }
                    else if (d_value == "region")
                    {
                        // just read everything until newline.
                        string region_name = "";
                        while (true)
                        {
                            token = tokenizer.ReadToken();
                            if (token == null || token.Type == ZScriptTokenType.Newline)
                            {
                                break;
                            }
                            region_name += token.Value;
                        }
                        DecorateCategoryInfo region   = new DecorateCategoryInfo();
                        string[]             cattitle = region_name.Split(DataManager.CATEGORY_SPLITTER, StringSplitOptions.RemoveEmptyEntries);
                        if (regions.Count > 0)
                        {
                            region.Category.AddRange(regions.Last().Category);
                            region.Properties = new Dictionary <string, List <string> >(regions.Last().Properties, StringComparer.OrdinalIgnoreCase);
                        }
                        region.Category.AddRange(cattitle);
                        regions.Add(region);
                    }
                    else if (d_value == "endregion")
                    {
                        // read everything until newline too?
                        // - only if it causes problems
                        if (regions.Count > 0)
                        {
                            regions.RemoveAt(regions.Count - 1);         // remove last region from the list
                        }
                        else
                        {
                            LogWarning("Superfluous #endregion found without corresponding #region");
                        }
                    }
                    else
                    {
                        ReportError("Unknown preprocessor directive: " + directive.Value);
                        return(false);
                    }
                    break;
                }

                case ZScriptTokenType.Identifier:
                {
                    // identifier can be one of: class, enum, const, struct
                    // the only type that we really care about is class, as it's the one that has all actors.
                    switch (token.Value.ToLowerInvariant())
                    {
                    case "extend":
                        tokenizer.SkipWhitespace();
                        token = tokenizer.ExpectToken(ZScriptTokenType.Identifier);
                        if (token == null || !token.IsValid || ((token.Value.ToLowerInvariant() != "class") && (token.Value.ToLowerInvariant() != "struct")))
                        {
                            ReportError("Expected class or struct, got " + ((Object)token ?? "<null>").ToString());
                            return(false);
                        }
                        if (!ParseClassOrStruct((token.Value.ToLowerInvariant() == "struct"), true, (regions.Count > 0 ? regions.Last() : null)))
                        {
                            return(false);
                        }
                        break;

                    case "class":
                        // todo parse class
                        if (!ParseClassOrStruct(false, false, (regions.Count > 0 ? regions.Last() : null)))
                        {
                            return(false);
                        }
                        break;

                    case "struct":
                        // todo parse struct
                        if (!ParseClassOrStruct(true, false, null))
                        {
                            return(false);
                        }
                        break;

                    case "const":
                        if (!ParseConst())
                        {
                            return(false);
                        }
                        break;

                    case "enum":
                        if (!ParseEnum())
                        {
                            return(false);
                        }
                        break;

                    case "version":
                        // expect a string. do nothing about it.
                        tokenizer.SkipWhitespace();
                        token = tokenizer.ExpectToken(ZScriptTokenType.String);
                        if (token == null || !token.IsValid)
                        {
                            ReportError("Expected version string, got " + ((Object)token ?? "<null>").ToString());
                            return(false);
                        }
                        break;

                    default:
                        ReportError("Expected preprocessor statement, const, enum or class declaraction, got " + token);
                        return(false);
                    }
                    break;
                }
                }
            }

            return(true);
        }
            internal bool Process()
            {
                RestoreStreamData();

                bool isactor = false;
                ZScriptClassStructure _pstruct = this;

                while (_pstruct != null)
                {
                    if (_pstruct.ClassName.ToLowerInvariant() == "actor")
                    {
                        isactor = true;
                        break;
                    }

                    if (_pstruct.ParentName != null)
                    {
                        string _pname = _pstruct.ParentName.ToLowerInvariant();
                        Parser.allclasses.TryGetValue(_pname, out _pstruct);
                    }
                    else
                    {
                        _pstruct = null;
                    }
                }

                string log_inherits = ((ParentName != null) ? "inherits " + ParentName : "");

                if (ReplacementName != null)
                {
                    log_inherits += ((log_inherits.Length > 0) ? ", " : "") + "replaces " + ReplacementName;
                }
                if (log_inherits.Length > 0)
                {
                    log_inherits = " (" + log_inherits + ")";
                }

                if (isactor)
                {
                    Actor = new ZScriptActorStructure(Parser, Region, ClassName, ReplacementName, ParentName);
                    if (Parser.HasError)
                    {
                        Actor = null;
                        return(false);
                    }

                    // check actor replacement.
                    Parser.archivedactors[Actor.ClassName.ToLowerInvariant()]     = Actor;
                    Parser.realarchivedactors[Actor.ClassName.ToLowerInvariant()] = Actor;
                    if (Actor.CheckActorSupported())
                    {
                        Parser.actors[Actor.ClassName.ToLowerInvariant()] = Actor;
                    }

                    // Replace an actor?
                    if (Actor.ReplacesClass != null)
                    {
                        if (Parser.GetArchivedActorByName(Actor.ReplacesClass, false) != null)
                        {
                            Parser.archivedactors[Actor.ReplacesClass.ToLowerInvariant()] = Actor;
                        }
                        else
                        {
                            Parser.LogWarning("Unable to find \"" + Actor.ReplacesClass + "\" class to replace, while parsing \"" + Actor.ClassName + "\"");
                        }

                        if (Actor.CheckActorSupported() && Parser.GetActorByName(Actor.ReplacesClass) != null)
                        {
                            Parser.actors[Actor.ReplacesClass.ToLowerInvariant()] = Actor;
                        }
                    }

                    //mxd. Add to current text resource
                    if (!Parser.scriptresources[TextResourcePath].Entries.Contains(Actor.ClassName))
                    {
                        Parser.scriptresources[TextResourcePath].Entries.Add(Actor.ClassName);
                    }
                }

                //Parser.LogWarning(string.Format("Parsed {0}class {1}{2}", isactor?"actor ":"", ClassName, log_inherits));

                return(true);
            }