package burp; import java.util.ArrayList; import java.util.List; /** * Minimal Markdown -> HTML renderer for Burp UI. * Supports: headings (#..######), fenced code blocks (```), inline code (`), * bold (**), lists (-/*), paragraphs, and basic escaping. * * Not a full CommonMark implementation; kept dependency-free on purpose. */ final class MarkdownRenderer { private MarkdownRenderer() {} static String toHtml(String markdown) { if (markdown == null) markdown = ""; List lines = splitLines(markdown); StringBuilder out = new StringBuilder(4096); out.append("") .append(""); boolean inCode = false; boolean inList = false; StringBuilder codeBuf = new StringBuilder(); for (String raw : lines) { String line = raw == null ? "" : raw; if (line.trim().startsWith("```")) { if (!inCode) { inCode = true; codeBuf.setLength(0); } else { // close code out.append("
")
                            .append(escapeHtml(codeBuf.toString()))
                            .append("
"); inCode = false; } continue; } if (inCode) { codeBuf.append(line).append("\n"); continue; } String trimmed = line.trim(); if (trimmed.isEmpty()) { if (inList) { out.append(""); inList = false; } out.append("
"); continue; } // headings int h = headingLevel(trimmed); if (h > 0) { if (inList) { out.append(""); inList = false; } String text = trimmed.substring(h).trim(); out.append("") .append(inlineFormat(text)) .append(""); continue; } // list items if (trimmed.startsWith("- ") || trimmed.startsWith("* ")) { if (!inList) { out.append(""); inList = false; } out.append("

").append(inlineFormat(trimmed)).append("

"); } if (inCode) { out.append("
")
                    .append(escapeHtml(codeBuf.toString()))
                    .append("
"); } if (inList) { out.append(""); } out.append(""); return out.toString(); } private static int headingLevel(String s) { int i = 0; while (i < s.length() && s.charAt(i) == '#') i++; if (i >= 1 && i <= 6 && i < s.length() && Character.isWhitespace(s.charAt(i))) return i; return 0; } private static String inlineFormat(String text) { // escape first, then apply simple replacements using placeholders String escaped = escapeHtml(text); // inline code: `code` escaped = replaceInlineCode(escaped); // bold: **text** escaped = replaceBold(escaped); return escaped; } private static String replaceInlineCode(String s) { StringBuilder out = new StringBuilder(s.length() + 16); boolean in = false; StringBuilder buf = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == '`') { if (!in) { in = true; buf.setLength(0); } else { out.append("").append(buf).append(""); in = false; } continue; } if (in) buf.append(c); else out.append(c); } if (in) { // unmatched backtick: keep as literal out.append("`").append(buf); } return out.toString(); } private static String replaceBold(String s) { // simple non-nested **...** StringBuilder out = new StringBuilder(s.length() + 16); int i = 0; while (i < s.length()) { int start = s.indexOf("**", i); if (start < 0) { out.append(s.substring(i)); break; } int end = s.indexOf("**", start + 2); if (end < 0) { out.append(s.substring(i)); break; } out.append(s.substring(i, start)); out.append("").append(s, start + 2, end).append(""); i = end + 2; } return out.toString(); } private static String escapeHtml(String s) { if (s == null) return ""; return s.replace("&", "&") .replace("<", "<") .replace(">", ">") .replace("\"", """); } private static List splitLines(String s) { String[] parts = s.split("\\r?\\n", -1); List lines = new ArrayList<>(parts.length); for (String p : parts) lines.add(p); return lines; } }