in freemarker-core/src/main/java/freemarker/template/utility/StringUtil.java [110:200]
private static String XMLOrHTMLEnc(String s, boolean escGT, boolean escQuot, char[] apos) {
final int ln = s.length();
// First we find out if we need to escape, and if so, what the length of the output will be:
int firstEscIdx = -1;
int lastEscIdx = 0;
int plusOutLn = 0;
for (int i = 0; i < ln; i++) {
escape: do {
final char c = s.charAt(i);
switch (c) {
case '<':
plusOutLn += LT.length - 1;
break;
case '>':
if (!(escGT || maybeCDataEndGT(s, i))) {
break escape;
}
plusOutLn += GT.length - 1;
break;
case '&':
plusOutLn += AMP.length - 1;
break;
case '"':
if (!escQuot) {
break escape;
}
plusOutLn += QUOT.length - 1;
break;
case '\'': // apos
if (apos == null) {
break escape;
}
plusOutLn += apos.length - 1;
break;
default:
break escape;
}
if (firstEscIdx == -1) {
firstEscIdx = i;
}
lastEscIdx = i;
} while (false);
}
if (firstEscIdx == -1) {
return s; // Nothing to escape
} else {
final char[] esced = new char[ln + plusOutLn];
if (firstEscIdx != 0) {
s.getChars(0, firstEscIdx, esced, 0);
}
int dst = firstEscIdx;
scan: for (int i = firstEscIdx; i <= lastEscIdx; i++) {
final char c = s.charAt(i);
switch (c) {
case '<':
dst = shortArrayCopy(LT, esced, dst);
continue scan;
case '>':
if (!(escGT || maybeCDataEndGT(s, i))) {
break;
}
dst = shortArrayCopy(GT, esced, dst);
continue scan;
case '&':
dst = shortArrayCopy(AMP, esced, dst);
continue scan;
case '"':
if (!escQuot) {
break;
}
dst = shortArrayCopy(QUOT, esced, dst);
continue scan;
case '\'': // apos
if (apos == null) {
break;
}
dst = shortArrayCopy(apos, esced, dst);
continue scan;
}
esced[dst++] = c;
}
if (lastEscIdx != ln - 1) {
s.getChars(lastEscIdx + 1, ln, esced, dst);
}
return String.valueOf(esced);
}
}