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