private static async Task <Tuple <string, string, string> > TitlePartitionAsync(WikiSite site, IWikiFamily family, string rawTitle, int defaultNamespace) { // Tuple<interwiki, namespace, title> Debug.Assert(site != null); Debug.Assert(rawTitle != null); var title = rawTitle; if (title.Length == 0) { goto EMPTY_TITLE; } var state = 0; /* * state accepts * 0 LeadingBlank * 1 Namespace / Interwiki * 2 Page title */ string interwiki = null, nsname = null, pagetitle = null; while (title != null) { var parts = title.Split(new[] { ':' }, 2); var part = parts[0].Trim(' ', '_'); switch (state) { case 0: if (part.Length > 0) { goto case 1; } // Initial colon indicates main namespace rather than default. nsname = ""; state = 1; break; case 1: // Make sure there's a colon ahead; otherwise we just treat it as a normal title. if (parts.Length == 1) { goto case 2; } NamespaceInfo ns; if (site.Namespaces.TryGetValue(part, out ns)) { // This is a namespace name. nsname = ns.CustomName; state = 2; } else { if (family != null) { var normalizedPart = family.TryNormalize(part); if (normalizedPart != null) { var nextSite = await family.GetSiteAsync(part); if (nextSite != null) { // We have bumped into another wiki, hooray! interwiki = normalizedPart; site = nextSite; // state will still be 1, to parse namespace or other interwikis (rare) } } } else if (site.InterwikiMap.Contains(part)) { // Otherwise, check whether this is an interwiki prefix. interwiki = part.ToLowerInvariant(); // For interwiki, we do not parse namespace name. // Instead, we treat it as a part of page title. nsname = null; state = 2; } else { // So this is only the beginning of a normal title. goto case 2; } } break; case 2: pagetitle = Utility.NormalizeTitlePart(title, site.SiteInfo.IsTitleCaseSensitive); goto END_OF_PARSING; } title = parts[1]; } END_OF_PARSING: Debug.Assert(pagetitle != null, "pagetitle != null"); if (pagetitle.Length == 0) { goto EMPTY_TITLE; } // nsname == null means that the expression has interwiki prefix, while family == null if (nsname == null && interwiki == null) { nsname = site.Namespaces[defaultNamespace].CustomName; } return(Tuple.Create(interwiki, nsname, pagetitle)); EMPTY_TITLE: throw new ArgumentException($"The title \"{rawTitle}\" does not contain page title."); }
private static async Task <Tuple <WikiSite, string, string, string> > TitlePartitionAsync(WikiSite site, IWikiFamily family, string rawTitle, int defaultNamespace) { // Tuple<interwiki, namespace, title, targetSite> Debug.Assert(site != null || family != null); Debug.Assert(rawTitle != null); var title = rawTitle; if (title.Length == 0) { return(null); } var state = 0; /* * state accepts * 0 LeadingBlank * 1 Namespace / Interwiki * 2 Page title */ string interwiki = null, nsname = null, pagetitle = null; while (title != null) { var parts = title.Split(new[] { ':' }, 2); var part = parts[0].Trim(' ', '_'); switch (state) { case 0: if (part.Length > 0) { goto case 1; } // Initial colon indicates main namespace rather than default. nsname = ""; state = 1; break; case 1: // Make sure there's a colon ahead; otherwise we just treat it as a normal title. if (parts.Length == 1) { goto case 2; } string normalizedInterwikiPrefix; if (site != null && site.Namespaces.TryGetValue(part, out var ns)) { // This is a namespace name. nsname = ns.CustomName; state = 2; } else if (family != null && (normalizedInterwikiPrefix = family.TryNormalize(part)) != null) { // This is a known prefix in the specified WikiFamily. var nextSite = await family.GetSiteAsync(part); if (nextSite == null) { Debug.Assert(false, $"{family} returned null for prefix: {normalizedInterwikiPrefix}. " + "IWikiFamily.TryNormalize should return null for in-existent interwiki prefixes."); } else { // We have bumped into another wiki, hooray! interwiki = normalizedInterwikiPrefix; site = nextSite; // state will still be 1, to parse namespace or other interwikis (rare) } } else if (site != null && site.InterwikiMap.Contains(part)) { // Otherwise, check whether this is an interwiki prefix. interwiki = part.ToLowerInvariant(); // For interwiki, we do not parse namespace name. // Instead, we treat it as a part of page title. nsname = null; state = 2; } else { // So this is only the beginning of a normal title. goto case 2; } break; case 2: pagetitle = Utility.NormalizeTitlePart(title, site?.SiteInfo.IsTitleCaseSensitive ?? true); goto END_OF_PARSING; } title = parts[1]; } END_OF_PARSING: Debug.Assert(pagetitle != null, "pagetitle != null"); if (pagetitle.Length == 0) { return(null); } // nsname == null but interwiki != null means that the expression has interwiki prefix, while family == null if (nsname == null && interwiki == null) { // If site is (still) null, we will have error reported in the caller. nsname = site?.Namespaces[defaultNamespace].CustomName; } return(Tuple.Create(site, interwiki, nsname, pagetitle)); }