1 |
package blackfriday |
2 |
|
3 |
import ( |
4 |
"html" |
5 |
"io" |
6 |
) |
7 |
|
8 |
var htmlEscaper = [256][]byte{ |
9 |
'&': []byte("&"), |
10 |
'<': []byte("<"), |
11 |
'>': []byte(">"), |
12 |
'"': []byte("""), |
13 |
} |
14 |
|
15 |
func escapeHTML(w io.Writer, s []byte) { |
16 |
escapeEntities(w, s, false) |
17 |
} |
18 |
|
19 |
func escapeAllHTML(w io.Writer, s []byte) { |
20 |
escapeEntities(w, s, true) |
21 |
} |
22 |
|
23 |
func escapeEntities(w io.Writer, s []byte, escapeValidEntities bool) { |
24 |
var start, end int |
25 |
for end < len(s) { |
26 |
escSeq := htmlEscaper[s[end]] |
27 |
if escSeq != nil { |
28 |
isEntity, entityEnd := nodeIsEntity(s, end) |
29 |
if isEntity && !escapeValidEntities { |
30 |
w.Write(s[start : entityEnd+1]) |
31 |
start = entityEnd + 1 |
32 |
} else { |
33 |
w.Write(s[start:end]) |
34 |
w.Write(escSeq) |
35 |
start = end + 1 |
36 |
} |
37 |
} |
38 |
end++ |
39 |
} |
40 |
if start < len(s) && end <= len(s) { |
41 |
w.Write(s[start:end]) |
42 |
} |
43 |
} |
44 |
|
45 |
func nodeIsEntity(s []byte, end int) (isEntity bool, endEntityPos int) { |
46 |
isEntity = false |
47 |
endEntityPos = end + 1 |
48 |
|
49 |
if s[end] == '&' { |
50 |
for endEntityPos < len(s) { |
51 |
if s[endEntityPos] == ';' { |
52 |
if entities[string(s[end:endEntityPos+1])] { |
53 |
isEntity = true |
54 |
break |
55 |
} |
56 |
} |
57 |
if !isalnum(s[endEntityPos]) && s[endEntityPos] != '&' && s[endEntityPos] != '#' { |
58 |
break |
59 |
} |
60 |
endEntityPos++ |
61 |
} |
62 |
} |
63 |
|
64 |
return isEntity, endEntityPos |
65 |
} |
66 |
|
67 |
func escLink(w io.Writer, text []byte) { |
68 |
unesc := html.UnescapeString(string(text)) |
69 |
escapeHTML(w, []byte(unesc)) |
70 |
} |