1 |
yakumo_izuru |
1.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 |
|
|
} |