Sanitize emphasis

This commit is contained in:
hns 2009-09-21 12:47:51 +00:00
parent fc689d9a12
commit 219a5df9ff

View file

@ -18,7 +18,7 @@ public class MarkdownProcessor {
private boolean listParagraphs = false; private boolean listParagraphs = false;
private int codeEndMarker = 0; private int codeEndMarker = 0;
private ElementStack stack = new ElementStack(); private ElementStack stack = new ElementStack();
private HashMap spanTags; private Emphasis[] emph = new Emphasis[2];
private String result = null; private String result = null;
@ -249,7 +249,6 @@ public class MarkdownProcessor {
private synchronized void secondPass() { private synchronized void secondPass() {
state = NEWLINE; state = NEWLINE;
stack.add(new BaseElement()); stack.add(new BaseElement());
spanTags = new HashMap();
buffer = new StringBuilder((int) (length * 1.2)); buffer = new StringBuilder((int) (length * 1.2));
line = 1; line = 1;
boolean escape = false; boolean escape = false;
@ -320,9 +319,9 @@ public class MarkdownProcessor {
if (state == HEADER) { if (state == HEADER) {
if (c == '#') { if (c == '#') {
((Element) stack.peek()).m ++; ((Element) stack.peek()).mod++;
} else { } else {
((Element) stack.peek()).m = 0; ((Element) stack.peek()).mod = 0;
} }
} }
@ -346,8 +345,8 @@ public class MarkdownProcessor {
} }
if (state == HEADER) { if (state == HEADER) {
Element header = (Element) stack.pop(); Element header = (Element) stack.pop();
if (header.m > 0) { if (header.mod > 0) {
buffer.setLength(buffer.length() - header.m); buffer.setLength(buffer.length() - header.mod);
} }
header.close(); header.close();
} }
@ -415,6 +414,14 @@ public class MarkdownProcessor {
} }
private boolean checkEmphasis(char c) { private boolean checkEmphasis(char c) {
for (int l = 1; l >= 0; l--) {
if (emph[l] != null && emph[l].end == i) {
emph[l].close();
i += emph[l].mod;
emph[l] = null;
return true;
}
}
if (c == '*' || c == '_') { if (c == '*' || c == '_') {
int n = 1; int n = 1;
int j = i + 1; int j = i + 1;
@ -424,68 +431,50 @@ public class MarkdownProcessor {
} }
int found = n; int found = n;
boolean isStartTag = j < length - 1 && !Character.isWhitespace(chars[j]); boolean isStartTag = j < length - 1 && !Character.isWhitespace(chars[j]);
boolean isEndTag = i > 0 && !Character.isWhitespace(chars[i - 1]); if (isStartTag && (emph[0] == null || emph[1] == null)) {
boolean hasStrong = spanTags.get(Integer.valueOf(2)) != null; List possibleEndTags = new ArrayList();
boolean hasEmphasis = spanTags.get(Integer.valueOf(1)) != null;
if (isStartTag && (!hasStrong || !hasEmphasis)) {
List matchingEndTags = new ArrayList();
char lastChar = 0; char lastChar = 0;
int count = 0; int count = 0;
boolean escape = false;
for (int k = j; k < length; k++) { for (int k = j; k < length; k++) {
if (chars[k] == '\n' && lastChar == '\n') { if (chars[k] == '\n' && lastChar == '\n') {
break; break;
} }
if (chars[k] == c) {
count += 1;
} else {
if (count > 0 && !Character.isWhitespace(chars[k - count - 1])) {
matchingEndTags.add(Integer.valueOf(count));
}
count = 0;
}
lastChar = chars[k]; lastChar = chars[k];
} System.err.println(k + ": " + chars[k]);
String[] tryElements = { if (escape) {
hasEmphasis ? null : "em", escape = false;
hasStrong || n < 2 ? null : "strong" } else {
}; if (chars[k] == '\\') {
Stack matchedElements = new Stack(); escape = true;
for (int l = tryElements.length - 1; l >= 0; l--) { } else if (chars[k] == '`') {
for (int k = 0; k < matchingEndTags.size(); k++) { k = skipCodeSpan(k);
// FIXME bogus check } else if (chars[k] == c) {
if (matchedElements.size() == tryElements.length) { count += 1;
break; } else {
} if (count > 0 && !Character.isWhitespace(chars[k - count - 1])) {
if (n > l && tryElements[l] != null && ((Integer) matchingEndTags.get(k)).intValue() > l) { // add an int array to possible end tags: [position, nuberOfTokens]
matchedElements.add(tryElements[l]); possibleEndTags.add(new int[] {k - count, count});
n -= l + 1; }
matchingEndTags.set(k, Integer.valueOf(((Integer) matchingEndTags.get(k)).intValue() - l + 1)); count = 0;
tryElements[l] = null;
} }
} }
} }
while (matchedElements.size() > 0) { for (int l = 1; l >= 0; l--) {
String ctor = (String) matchedElements.pop(); if (emph[l] == null && n > l) {
Element elem = "em".equals(ctor) ? (Element) new Emphasis() : new Strong(); emph[l] = checkEmphasisInternal(l + 1, possibleEndTags);
elem.open(); if (emph[l] != null) {
spanTags.put(Integer.valueOf("strong".equals(ctor) ? 2 : 1), elem); n -= l + 1;
} }
}
if (isEndTag) {
for (int z = 2; z > 0; z--) {
Element elem = (Element) spanTags.get(Integer.valueOf(z));
if (elem != null && elem.m <= n) {
spanTags.remove(Integer.valueOf(z));
elem.close();
n -= elem.m;
} }
} }
} }
if (n == found) { if (n == found) {
return false; return false;
} }
// write out remaining token chars
for (int m = 0; m < n; m++) { for (int m = 0; m < n; m++) {
buffer.append(c); buffer.append(c);
} }
@ -495,6 +484,20 @@ public class MarkdownProcessor {
return false; return false;
} }
private Emphasis checkEmphasisInternal(int length, List possibleEndTags) {
for (int k = 0; k < possibleEndTags.size(); k++) {
int[] possibleEndTag = (int[]) possibleEndTags.get(k);
if (possibleEndTag[1] >= length) {
Emphasis elem = new Emphasis(length, possibleEndTag[0]);
elem.open();
possibleEndTag[0] += length;
possibleEndTag[1] -= length;
return elem;
}
}
return null;
}
private boolean checkCodeSpan(char c) { private boolean checkCodeSpan(char c) {
if (c != '`') { if (c != '`') {
return false; return false;
@ -542,6 +545,37 @@ public class MarkdownProcessor {
return true; return true;
} }
// find the end of a code span starting at start
private int skipCodeSpan(int start) {
int n = 0; // additional backticks to match
int j = start + 1;
while(j < length && chars[j] == '`') {
n += 1;
j += 1;
}
outer: while(j < length) {
if (chars[j] == '`') {
if (n == 0) {
break;
} else {
if (j + n >= length) {
return start + 1;
}
for (int k = j + 1; k <= j + n; k++) {
if (chars[k] != '`') {
break;
} else if (k == j + n) {
j = k;
break outer;
}
}
}
}
j += 1;
}
return j;
}
private boolean checkLink(char c) { private boolean checkLink(char c) {
return checkLinkInternal(c, i + 1, false); return checkLinkInternal(c, i + 1, false);
} }
@ -1089,7 +1123,7 @@ public class MarkdownProcessor {
class Element { class Element {
String tag; String tag;
int nesting, m; int nesting, mod;
void open() { void open() {
openTag(tag, buffer); openTag(tag, buffer);
@ -1145,16 +1179,11 @@ public class MarkdownProcessor {
} }
class Emphasis extends Element { class Emphasis extends Element {
Emphasis() { int end;
this.tag = "em"; Emphasis(int mod, int end) {
this.m = 1; this.mod = mod;
} this.end = end;
} this.tag = mod == 1 ? "em" : "strong";
class Strong extends Element {
Strong() {
this.tag = "strong";
this.m = 2;
} }
} }