internal WikitextParserOptions DefensiveCopy() { // This method should be thread-safe when there are concurrent DefensiveCopy calls. if (_DefensiveCopy != null) { return(_DefensiveCopy); } var inst = (WikitextParserOptions)MemberwiseClone(); inst._DefensiveCopy = inst; inst._ParserTags = ParserTags == null || ReferenceEquals(ParserTags, DefaultParserTags) ? DefaultParserTagsSet : new HashSet <string>(ParserTags, StringComparer.OrdinalIgnoreCase); inst._SelfClosingOnlyTags = SelfClosingOnlyTags == null || ReferenceEquals(SelfClosingOnlyTags, DefaultSelfClosingOnlyTags) ? DefaultSelfClosingOnlyTagsSet : new HashSet <string>(SelfClosingOnlyTags, StringComparer.OrdinalIgnoreCase); if (ImageNamespaceNames == null || ReferenceEquals(ImageNamespaceNames, DefaultImageNamespaceNames)) { inst._ImageNamespaceNames = DefaultImageNamespaceNamesSet; inst.ImageNamespaceRegexp = DefaultImageNamespaceNameRegexp; } else { var collection = ImageNamespaceNames as ICollection <string> ?? ImageNamespaceNames.ToList(); inst.ImageNamespaceRegexp = string.Join("|", collection.Select(Regex.Escape)); inst._ImageNamespaceNames = new HashSet <string>(collection, StringComparer.OrdinalIgnoreCase); } if (inst.MagicTemplateNames == null || ReferenceEquals(MagicTemplateNames, DefaultMagicTemplateNames)) { inst.CaseSensitiveMagicTemplateNamesSet = DefaultCaseSensitiveMagicTemplatesSet; inst.CaseInsensitiveMagicTemplateNamesSet = DefaultCaseInsensitiveMagicTemplatesSet; } else { inst.CaseSensitiveMagicTemplateNamesSet = new HashSet <string>(); inst.CaseInsensitiveMagicTemplateNamesSet = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (var tn in MagicTemplateNames) { if (tn.IsCaseSensitive) { inst.CaseSensitiveMagicTemplateNamesSet.Add(tn.Name); } else { inst.CaseInsensitiveMagicTemplateNamesSet.Add(tn.Name); } } } inst._MagicTemplateNames = null; _DefensiveCopy = inst; return(inst); }
public Wikitext Parse(WikitextParserOptions options, IWikitextParserLogger logger, string wikitext, CancellationToken cancellationToken) { if (wikitext == null) { throw new ArgumentNullException(nameof(wikitext)); } cancellationToken.ThrowIfCancellationRequested(); // Initialize this.options = options?.DefensiveCopy() ?? WikitextParserOptions.DefaultOptionsCopy; this.logger = logger; fulltext = wikitext; lineNumber = linePosition = 0; position = 0; contextStack = new Stack <ParsingContext>(); this.cancellationToken = cancellationToken; try { // Then parse logger?.NotifyParsingStarted(wikitext); var root = ParseWikitext(); // State check if (position < fulltext.Length) { throw new InvalidParserStateException( "Detected unparsed wikitext after parsing. There might be a bug with parser."); } if (contextStack.Count > 0) { throw new InvalidParserStateException( "Detected remaining ParsingContext on context stack. There might be a bug with parser."); } logger?.NotifyParsingFinished(); return(root); } finally { // Cleanup fulltext = null; contextStack = null; options = null; logger = null; } }
internal WikitextParserOptions DefensiveCopy() { // This method should be thread-safe when there are concurrent DefensiveCopy calls. if (_DefensiveCopy != null) { return(_DefensiveCopy); } var inst = (WikitextParserOptions)MemberwiseClone(); inst._DefensiveCopy = inst; inst._ParserTags = ParserTags == null || ReferenceEquals(ParserTags, DefaultParserTags) ? DefaultParserTagsSet : new HashSet <string>(ParserTags, StringComparer.OrdinalIgnoreCase); inst._SelfClosingOnlyTags = SelfClosingOnlyTags == null || ReferenceEquals(SelfClosingOnlyTags, DefaultSelfClosingOnlyTags) ? DefaultSelfClosingOnlyTagsSet : new HashSet <string>(SelfClosingOnlyTags, StringComparer.OrdinalIgnoreCase); if (inst.MagicTemplateNames == null || ReferenceEquals(MagicTemplateNames, DefaultMagicTemplateNames)) { inst.CaseSensitiveMagicTemplateNamesSet = DefaultCaseSensitiveMagicTemplatesSet; inst.CaseInsensitiveMagicTemplateNamesSet = DefaultCaseInsensitiveMagicTemplatesSet; } else { inst.CaseSensitiveMagicTemplateNamesSet = new HashSet <string>(); inst.CaseInsensitiveMagicTemplateNamesSet = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (var tn in MagicTemplateNames) { if (tn.IsCaseSensitive) { inst.CaseSensitiveMagicTemplateNamesSet.Add(tn.Name); } else { inst.CaseInsensitiveMagicTemplateNamesSet.Add(tn.Name); } } } inst._MagicTemplateNames = null; _DefensiveCopy = inst; return(inst); }