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 if len(strings.Trim(prefix, " \t"))+len(strings.Trim(indent, " \t")) > 0 {
95
96 invalidPrefix, invalidIndent := prefix, indent
97 prefix = strings.Repeat(" ", len(prefix))
98 indent = strings.Repeat(" ", len(indent))
99 defer func() {
100 b := dst[dstLen:]
101 for i := bytes.IndexByte(b, '\n'); i >= 0; i = bytes.IndexByte(b, '\n') {
102 b = b[i+len("\n"):]
103 n := len(b) - len(bytes.TrimLeft(b, " "))
104 spaces := b[:n]
105 spaces = spaces[copy(spaces, invalidPrefix):]
106 for len(spaces) > 0 {
107 spaces = spaces[copy(spaces, invalidIndent):]
108 }
109 b = b[n:]
110 }
111 }()
112 }
113
114 dst, err := jsontext.AppendFormat(dst, src,
115 ReportErrorsWithLegacySemantics(true),
116 jsontext.AllowDuplicateNames(true),
117 jsontext.AllowInvalidUTF8(true),
118 jsontext.PreserveRawStrings(true),
119 jsontext.Multiline(true),
120 jsontext.WithIndentPrefix(prefix),
121 jsontext.WithIndent(indent))
122 if err != nil {
123 return dst[:dstLen], transformSyntacticError(err)
124 }
125
126
127 if n := len(src) - len(bytes.TrimRight(src, " \n\r\t")); n > 0 {
128 dst = append(dst, src[len(src)-n:]...)
129 }
130 return dst, nil
131 }
132
View as plain text