/// <summary> /// Collapses internal whitespace to single space, removes leading/trailing whitespace, folds case. /// </summary> private static string NormalizeReference(StringPart s) { if (s.Length == 0) return string.Empty; return NormalizeWhitespace(s.Source, s.StartIndex, s.Length).ToUpperInvariant(); }
/// <summary> /// Adds a new reference to the dictionary, if the label does not already exist there. /// Assumes that the length of the label does not exceed <see cref="Reference.MaximumReferenceLabelLength"/>. /// </summary> private static void AddReference(Dictionary<string, Reference> refmap, StringPart label, string url, string title) { var normalizedLabel = NormalizeReference(label); if (refmap.ContainsKey(normalizedLabel)) return; refmap.Add(normalizedLabel, new Reference(normalizedLabel, url, title)); }
/// <summary> /// Checks if the reference dictionary contains a reference with the given label and returns it, /// otherwise returns <c>null</c>. /// Returns <see cref="Reference.InvalidReference"/> if the reference label is not valid. /// </summary> private static Reference LookupReference(Dictionary<string, Reference> refmap, StringPart lab) { if (refmap == null) return null; if (lab.Length > Reference.MaximumReferenceLabelLength) return Reference.InvalidReference; string label = NormalizeReference(lab); Reference r; if (refmap.TryGetValue(label, out r)) return r; return null; }
/// <summary> /// Checks if the reference dictionary contains a reference with the given label and returns it, /// otherwise returns <see langword="null"/>. /// Returns <see cref="Reference.InvalidReference"/> if the reference label is not valid. /// </summary> private static Reference LookupReference(DocumentData data, StringPart lab) { if (data?.ReferenceMap == null) return null; if (lab.Length > Reference.MaximumReferenceLabelLength) return Reference.InvalidReference; string label = NormalizeReference(lab); Reference r; if (data.ReferenceMap.TryGetValue(label, out r)) return r; return null; }
public void Write(StringPart value) { if (value.Length == 0) return; if (this.Buffer.Length < value.Length) this.Buffer = new char[value.Length]; value.Source.CopyTo(value.StartIndex, this.Buffer, 0, value.Length); if (this._windowsNewLine) { var lastPos = value.StartIndex; var pos = lastPos; while (-1 != (pos = value.Source.IndexOf('\n', pos, value.Length - pos + value.StartIndex))) { var lastC = pos == 0 ? this._last : value.Source[pos - 1]; if (lastC != '\r') { this._inner.Write(this.Buffer, lastPos - value.StartIndex, pos - lastPos); this._inner.Write('\r'); lastPos = pos; } pos++; } this._inner.Write(this.Buffer, lastPos - value.StartIndex, value.Length - lastPos + value.StartIndex); } else { this._inner.Write(this.Buffer, 0, value.Length); } this._last = this.Buffer[value.Length - 1]; }
private void WriteEncodedHtml(StringPart text) { HtmlFormatterSlim.EscapeHtml(text, _target); }
private void Write(StringPart text) { _target.Write(text); }
private static Inline HandleRightSquareBracket(Subject subj, CommonMarkSettings settings) { // move past ']' subj.Position++; bool canClose; var istack = InlineStack.FindMatchingOpener(subj.LastPendingInline, InlineStack.InlineStackPriority.Links, '[', out canClose); if (istack != null) { // if the opener is "inactive" then it means that there was a nested link if (istack.DelimeterCount == -1) { InlineStack.RemoveStackEntry(istack, subj, istack, settings.InlineParserParameters); return new Inline("]", subj.Position - 1, subj.Position); } var endpos = subj.Position; // try parsing details for '[foo](/url "title")' or '[foo][bar]' var details = ParseLinkDetails(subj, settings); // try lookup of the brackets themselves if (details == null || details == Reference.SelfReference) { var startpos = istack.StartPosition; var label = new StringPart(subj.Buffer, startpos, endpos - startpos - 1); details = LookupReference(subj.ReferenceMap, label, settings); } if (details == Reference.InvalidReference) details = null; MatchSquareBracketStack(istack, subj, details, settings.InlineParserParameters); return null; } var inlText = new Inline("]", subj.Position - 1, subj.Position); if (canClose) { // note that the current implementation will not work if there are other inlines with priority // higher than Links. // to fix this the parsed link details should be added to the closer element in the stack. throw new NotSupportedException("It is not supported to have inline stack priority higher than Links."); ////istack = new InlineStack(); ////istack.Delimeter = '['; ////istack.StartingInline = inlText; ////istack.StartPosition = subj.Position; ////istack.Priority = InlineStack.InlineStackPriority.Links; ////istack.Flags = InlineStack.InlineStackFlags.Closer; ////InlineStack.AppendStackEntry(istack, subj); } return inlText; }
/// <summary> /// Parses the contents of [..] for a reference label. Only used for parsing /// reference definition labels for use with the reference dictionary because /// it does not properly parse nested inlines. /// /// Assumes the source starts with '[' character or spaces before '['. /// Returns null and does not advance if no matching ] is found. /// Note the precedence: code backticks have precedence over label bracket /// markers, which have precedence over *, _, and other inline formatting /// markers. So, 2 below contains a link while 1 does not: /// 1. [a link `with a ](/url)` character /// 2. [a link *with emphasized ](/url) text* /// </summary> private static StringPart? ParseReferenceLabel(Subject subj) { var startPos = subj.Position; var source = subj.Buffer; var len = subj.Length; while (subj.Position < len) { var c = subj.Buffer[subj.Position]; if (c == ' ' || c == '\n') { subj.Position++; continue; } else if (c == '[') { subj.Position++; break; } else { subj.Position = startPos; return null; } } var labelStartPos = subj.Position; len = subj.Position + Reference.MaximumReferenceLabelLength; if (len > source.Length) len = source.Length; subj.Position = source.IndexOfAny(BracketSpecialCharacters, subj.Position, len - subj.Position); while (subj.Position > -1) { var c = source[subj.Position]; if (c == '\\') { subj.Position += 2; if (subj.Position >= len) break; subj.Position = source.IndexOfAny(BracketSpecialCharacters, subj.Position, len - subj.Position); } else if (c == '[') { break; } else { var label = new StringPart(source, labelStartPos, subj.Position - labelStartPos); subj.Position++; return label; } } subj.Position = startPos; return null; }
/// <summary> /// Collapses internal whitespace to single space, removes leading/trailing whitespace, folds case. /// </summary> private static string NormalizeReference(StringPart s, CommonMarkSettings settings) { if (s.Length == 0) return string.Empty; var result = NormalizeWhitespace(s.Source, s.StartIndex, s.Length); if (0 == (settings.AdditionalFeatures & CommonMarkAdditionalFeatures.RespectReferenceCase)) result = result.ToUpperInvariant(); return result; }
/// <summary> /// Escapes special HTML characters. /// </summary> /// <remarks>Orig: escape_html(inp, preserve_entities)</remarks> internal static void EscapeHtml(StringPart input, HtmlTextWriter target) { if (input.Length == 0) return; int pos; int lastPos = input.StartIndex; char[] buffer; if (target.Buffer.Length < input.Length) buffer = target.Buffer = new char[input.Length]; else buffer = target.Buffer; input.Source.CopyTo(input.StartIndex, buffer, 0, input.Length); while ((pos = input.Source.IndexOfAny(EscapeHtmlCharacters, lastPos, input.Length - lastPos + input.StartIndex)) != -1) { target.Write(buffer, lastPos - input.StartIndex, pos - lastPos); lastPos = pos + 1; switch (input.Source[pos]) { case '<': target.WriteConstant(EscapeHtmlLessThan); break; case '>': target.WriteConstant(EscapeHtmlGreaterThan); break; case '&': target.WriteConstant(EscapeHtmlAmpersand); break; case '"': target.WriteConstant(EscapeHtmlQuote); break; } } target.Write(buffer, lastPos - input.StartIndex, input.Length - lastPos + input.StartIndex); }