// This parses the given decorate stream // Returns false on errors public override bool Parse(Stream stream, string sourcefilename) { base.Parse(stream, sourcefilename); // Keep local data Stream localstream = datastream; string localsourcename = sourcename; BinaryReader localreader = datareader; // Continue until at the end of the stream while (SkipWhitespace(true)) { // Read a token string objdeclaration = ReadToken(); if (objdeclaration != null) { objdeclaration = objdeclaration.ToLowerInvariant(); if (objdeclaration == "actor") { // Read actor structure ActorStructure actor = new ActorStructure(this); if (this.HasError) { break; } // Add the actor archivedactors[actor.ClassName.ToLowerInvariant()] = actor; if (actor.CheckActorSupported()) { actors[actor.ClassName.ToLowerInvariant()] = actor; } // Replace an actor? if (actor.ReplacesClass != null) { if (GetArchivedActorByName(actor.ReplacesClass) != null) { archivedactors[actor.ReplacesClass.ToLowerInvariant()] = actor; } else { General.ErrorLogger.Add(ErrorType.Warning, "Unable to find the DECORATE class '" + actor.ReplacesClass + "' to replace, while parsing '" + actor.ClassName + "'"); } if (actor.CheckActorSupported()) { if (GetActorByName(actor.ReplacesClass) != null) { actors[actor.ReplacesClass.ToLowerInvariant()] = actor; } } } } else if (objdeclaration == "#include") { // Include a file SkipWhitespace(true); string filename = ReadToken(); if (!string.IsNullOrEmpty(filename)) { // Strip the quotes filename = filename.Replace("\"", ""); // Callback to parse this file now if (OnInclude != null) { OnInclude(this, filename); } // Set our buffers back to continue parsing datastream = localstream; datareader = localreader; sourcename = localsourcename; if (HasError) { break; } } else { ReportError("Expected file name to include"); break; } } else if ((objdeclaration == "const") || (objdeclaration == "native")) { // We don't need this, ignore up to the first next ; while (SkipWhitespace(true)) { string t = ReadToken(); if ((t == ";") || (t == null)) { break; } } } else { // Unknown structure! // Best we can do now is just find the first { and then // follow the scopes until the matching } is found string token2; do { if (!SkipWhitespace(true)) { break; } token2 = ReadToken(); if (token2 == null) { break; } }while(token2 != "{"); int scopelevel = 1; do { if (!SkipWhitespace(true)) { break; } token2 = ReadToken(); if (token2 == null) { break; } if (token2 == "{") { scopelevel++; } if (token2 == "}") { scopelevel--; } }while(scopelevel > 0); } } } // Return true when no errors occurred return(ErrorDescription == null); }
// 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); } //mxd. Region-as-category stuff... List <DecorateCategoryInfo> regions = new List <DecorateCategoryInfo>(); //mxd // Keep local data Stream localstream = datastream; string localsourcename = sourcename; BinaryReader localreader = datareader; DataLocation locallocation = datalocation; //mxd string localtextresourcepath = textresourcepath; //mxd // Continue until at the end of the stream while (SkipWhitespace(true)) { // Read a token string objdeclaration = ReadToken(); if (!string.IsNullOrEmpty(objdeclaration)) { objdeclaration = objdeclaration.ToLowerInvariant(); if (objdeclaration == "$gzdb_skip") { break; } switch (objdeclaration) { case "actor": { // Read actor structure ActorStructure actor = new ActorStructure(this, (regions.Count > 0 ? regions[regions.Count - 1] : null)); if (this.HasError) { return(false); } // Add the actor archivedactors[actor.ClassName.ToLowerInvariant()] = actor; if (actor.CheckActorSupported()) { actors[actor.ClassName.ToLowerInvariant()] = actor; } // Replace an actor? if (actor.ReplacesClass != null) { if (GetArchivedActorByName(actor.ReplacesClass) != null) { archivedactors[actor.ReplacesClass.ToLowerInvariant()] = actor; } else { LogWarning("Unable to find \"" + actor.ReplacesClass + "\" class to replace, while parsing \"" + actor.ClassName + "\""); } if (actor.CheckActorSupported() && GetActorByName(actor.ReplacesClass) != null) { actors[actor.ReplacesClass.ToLowerInvariant()] = actor; } } //mxd. Add to current text resource if (!textresources[textresourcepath].Entries.Contains(actor.ClassName)) { textresources[textresourcepath].Entries.Add(actor.ClassName); } } break; case "#include": { //INFO: ZDoom DECORATE include paths can't be relative ("../actor.txt") //or absolute ("d:/project/actor.txt") //or have backward slashes ("info\actor.txt") //include paths are relative to the first parsed entry, not the current one //also include paths may or may not be quoted SkipWhitespace(true); string filename = StripQuotes(ReadToken(false)); //mxd. Don't skip newline //mxd. Sanity checks if (string.IsNullOrEmpty(filename)) { ReportError("Expected file name to include"); return(false); } //mxd. Check invalid path chars if (!CheckInvalidPathChars(filename)) { return(false); } //mxd. Absolute paths are not supported... if (Path.IsPathRooted(filename)) { ReportError("Absolute include paths are not supported by ZDoom"); return(false); } //mxd. Relative paths are not supported if (filename.StartsWith(RELATIVE_PATH_MARKER) || filename.StartsWith(CURRENT_FOLDER_PATH_MARKER) || filename.StartsWith(ALT_RELATIVE_PATH_MARKER) || filename.StartsWith(ALT_CURRENT_FOLDER_PATH_MARKER)) { ReportError("Relative include paths are not supported by ZDoom"); return(false); } //mxd. Backward slashes are not supported if (filename.Contains(Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture))) { ReportError("Only forward slashes are supported by ZDoom"); return(false); } //mxd. Already parsed? if (parsedlumps.Contains(filename)) { ReportError("Already parsed \"" + filename + "\". Check your include directives"); return(false); } //mxd. Add to collection parsedlumps.Add(filename); // Callback to parse this file now if (OnInclude != null) { OnInclude(this, filename); } //mxd. Bail out on error if (this.HasError) { return(false); } // Set our buffers back to continue parsing datastream = localstream; datareader = localreader; sourcename = localsourcename; datalocation = locallocation; //mxd textresourcepath = localtextresourcepath; //mxd } break; case "damagetype": //mxd // Get DamageType name SkipWhitespace(true); string damagetype = StripQuotes(ReadToken(false)); if (string.IsNullOrEmpty(damagetype)) { ReportError("Expected DamageType name"); return(false); } // Next should be "{" SkipWhitespace(true); if (!NextTokenIs("{")) { return(false); } // Skip the structure while (SkipWhitespace(true)) { string t = ReadToken(); if (string.IsNullOrEmpty(t) || t == "}") { break; } } // Add to collection if (!damagetypes.Contains(damagetype)) { damagetypes.Add(damagetype); } break; case "enum": case "native": case "const": while (SkipWhitespace(true)) { string t = ReadToken(); if (string.IsNullOrEmpty(t) || t == ";") { break; } } break; //mxd. Region-as-category handling case "#region": SkipWhitespace(false); string cattitle = ReadLine(); if (!string.IsNullOrEmpty(cattitle)) { // Make new category info string[] parts = cattitle.Split(DataManager.CATEGORY_SPLITTER, StringSplitOptions.RemoveEmptyEntries); DecorateCategoryInfo info = new DecorateCategoryInfo(); if (regions.Count > 0) { // Preserve nesting info.Category.AddRange(regions[regions.Count - 1].Category); info.Properties = new Dictionary <string, List <string> >(regions[regions.Count - 1].Properties); } info.Category.AddRange(parts); // Add to collection regions.Add(info); } break; //mxd. Region-as-category handling case "#endregion": if (regions.Count > 0) { regions.RemoveAt(regions.Count - 1); } else { LogWarning("Unexpected #endregion token"); } break; default: { //mxd. In some special cases (like the whole actor commented using "//") our special comments will be detected here... if (objdeclaration.StartsWith("$")) { if (regions.Count > 0) { // Store region property regions[regions.Count - 1].Properties[objdeclaration] = new List <string> { (SkipWhitespace(false) ? ReadLine() : "") }; } else { // Skip the whole line, then carry on ReadLine(); } break; } // Unknown structure! // Best we can do now is just find the first { and then // follow the scopes until the matching } is found string token2; do { if (!SkipWhitespace(true)) { break; } token2 = ReadToken(); if (string.IsNullOrEmpty(token2)) { break; } }while(token2 != "{"); int scopelevel = 1; do { if (!SkipWhitespace(true)) { break; } token2 = ReadToken(); if (string.IsNullOrEmpty(token2)) { break; } if (token2 == "{") { scopelevel++; } if (token2 == "}") { scopelevel--; } }while(scopelevel > 0); } break; } } } // Return true when no errors occurred return(ErrorDescription == null); }