1
2
3
4
5
6
7 package json
8
9 import (
10 "bytes"
11 "strings"
12
13 "encoding/json/jsontext"
14 )
15
16
17
18
19
20
21 func HTMLEscape(dst *bytes.Buffer, src []byte) {
22 dst.Grow(len(src))
23 dst.Write(appendHTMLEscape(dst.AvailableBuffer(), src))
24 }
25
26 func appendHTMLEscape(dst, src []byte) []byte {
27 const hex = "0123456789abcdef"
28
29
30 start := 0
31 for i, c := range src {
32 if c == '<' || c == '>' || c == '&' {
33 dst = append(dst, src[start:i]...)
34 dst = append(dst, '\\', 'u', '0', '0', hex[c>>4], hex[c&0xF])
35 start = i + 1
36 }
37
38 if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
39 dst = append(dst, src[start:i]...)
40 dst = append(dst, '\\', 'u', '2', '0', '2', hex[src[i+2]&0xF])
41 start = i + len("\u2029")
42 }
43 }
44 return append(dst, src[start:]...)
45 }
46
47
48
49 func Compact(dst *bytes.Buffer, src []byte) error {
50 dst.Grow(len(src))
51 b := dst.AvailableBuffer()
52 b, err := jsontext.AppendFormat(b, src,
53 ReportErrorsWithLegacySemantics(true),
54 jsontext.AllowDuplicateNames(true),
55 jsontext.AllowInvalidUTF8(true),
56 jsontext.PreserveRawStrings(true))
57 if err != nil {
58 return transformSyntacticError(err)
59 }
60 dst.Write(b)
61 return nil
62 }
63
64
65
66
67
68
69
70 const indentGrowthFactor = 2
71
72
73
74
75
76
77
78
79
80
81
82
83 func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
84 dst.Grow(indentGrowthFactor * len(src))
85 b := dst.AvailableBuffer()
86 b, err := appendIndent(b, src, prefix, indent)
87 dst.Write(b)
88 return err
89 }
90
91 func appendIndent(dst, src []byte, prefix, indent string) ([]byte, error) {
92
93 dstLen := len(dst)
94 invalidPrefix, invalidIndent := prefix, indent
95 replaceIndent := len(strings.Trim(prefix, " \t"))+len(strings.Trim(indent, " \t")) > 0
96 if replaceIndent {
97
98 prefix = strings.Repeat(" ", len(prefix))
99 indent = strings.Repeat(" ", len(indent))
100 }
101
102 dst, err := jsontext.AppendFormat(dst, src,
103 ReportErrorsWithLegacySemantics(true),
104 jsontext.AllowDuplicateNames(true),
105 jsontext.AllowInvalidUTF8(true),
106 jsontext.PreserveRawStrings(true),
107 jsontext.Multiline(true),
108 jsontext.WithIndentPrefix(prefix),
109 jsontext.WithIndent(indent))
110 if err != nil {
111 return dst[:dstLen], transformSyntacticError(err)
112 }
113
114
115 if replaceIndent {
116 b := dst[dstLen:]
117 for i := bytes.IndexByte(b, '\n'); i >= 0; i = bytes.IndexByte(b, '\n') {
118 b = b[i+len("\n"):]
119 n := len(b) - len(bytes.TrimLeft(b, " "))
120 spaces := b[:n]
121 spaces = spaces[copy(spaces, invalidPrefix):]
122 for len(spaces) > 0 {
123 spaces = spaces[copy(spaces, invalidIndent):]
124 }
125 b = b[n:]
126 }
127 }
128
129
130 if n := len(src) - len(bytes.TrimRight(src, " \n\r\t")); n > 0 {
131 dst = append(dst, src[len(src)-n:]...)
132 }
133 return dst, nil
134 }
135
View as plain text