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 jsontext.AllowDuplicateNames(true),
54 jsontext.AllowInvalidUTF8(true),
55 jsontext.PreserveRawStrings(true))
56 if err != nil {
57 return transformSyntacticError(err)
58 }
59 dst.Write(b)
60 return nil
61 }
62
63
64
65
66
67
68
69 const indentGrowthFactor = 2
70
71
72
73
74
75
76
77
78
79
80
81
82 func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
83 dst.Grow(indentGrowthFactor * len(src))
84 b := dst.AvailableBuffer()
85 b, err := appendIndent(b, src, prefix, indent)
86 dst.Write(b)
87 return err
88 }
89
90 func appendIndent(dst, src []byte, prefix, indent string) ([]byte, error) {
91
92 dstLen := len(dst)
93 if n := len(src) - len(bytes.TrimRight(src, " \n\r\t")); n > 0 {
94
95 defer func() {
96 if len(dst) > dstLen {
97 dst = append(dst, src[len(src)-n:]...)
98 }
99 }()
100 }
101
102 if len(strings.Trim(prefix, " \t"))+len(strings.Trim(indent, " \t")) > 0 {
103
104 invalidPrefix, invalidIndent := prefix, indent
105 prefix = strings.Repeat(" ", len(prefix))
106 indent = strings.Repeat(" ", len(indent))
107 defer func() {
108 b := dst[dstLen:]
109 for i := bytes.IndexByte(b, '\n'); i >= 0; i = bytes.IndexByte(b, '\n') {
110 b = b[i+len("\n"):]
111 n := len(b) - len(bytes.TrimLeft(b, " "))
112 spaces := b[:n]
113 spaces = spaces[copy(spaces, invalidPrefix):]
114 for len(spaces) > 0 {
115 spaces = spaces[copy(spaces, invalidIndent):]
116 }
117 b = b[n:]
118 }
119 }()
120 }
121
122 dst, err := jsontext.AppendFormat(dst, src,
123 jsontext.AllowDuplicateNames(true),
124 jsontext.AllowInvalidUTF8(true),
125 jsontext.PreserveRawStrings(true),
126 jsontext.Multiline(true),
127 jsontext.WithIndentPrefix(prefix),
128 jsontext.WithIndent(indent))
129 if err != nil {
130 return dst[:dstLen], transformSyntacticError(err)
131 }
132 return dst, nil
133 }
134
View as plain text