| | |
| | |
| | |
| |
|
| | |
| |
|
| | package json |
| |
|
| | import "bytes" |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func HTMLEscape(dst *bytes.Buffer, src []byte) { |
| | dst.Grow(len(src)) |
| | dst.Write(appendHTMLEscape(dst.AvailableBuffer(), src)) |
| | } |
| |
|
| | func appendHTMLEscape(dst, src []byte) []byte { |
| | |
| | |
| | start := 0 |
| | for i, c := range src { |
| | if c == '<' || c == '>' || c == '&' { |
| | dst = append(dst, src[start:i]...) |
| | dst = append(dst, '\\', 'u', '0', '0', hex[c>>4], hex[c&0xF]) |
| | start = i + 1 |
| | } |
| | |
| | if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 { |
| | dst = append(dst, src[start:i]...) |
| | dst = append(dst, '\\', 'u', '2', '0', '2', hex[src[i+2]&0xF]) |
| | start = i + len("\u2029") |
| | } |
| | } |
| | return append(dst, src[start:]...) |
| | } |
| |
|
| | |
| | |
| | func Compact(dst *bytes.Buffer, src []byte) error { |
| | dst.Grow(len(src)) |
| | b := dst.AvailableBuffer() |
| | b, err := appendCompact(b, src, false) |
| | dst.Write(b) |
| | return err |
| | } |
| |
|
| | func appendCompact(dst, src []byte, escape bool) ([]byte, error) { |
| | origLen := len(dst) |
| | scan := newScanner() |
| | defer freeScanner(scan) |
| | start := 0 |
| | for i, c := range src { |
| | if escape && (c == '<' || c == '>' || c == '&') { |
| | if start < i { |
| | dst = append(dst, src[start:i]...) |
| | } |
| | dst = append(dst, '\\', 'u', '0', '0', hex[c>>4], hex[c&0xF]) |
| | start = i + 1 |
| | } |
| | |
| | if escape && c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 { |
| | if start < i { |
| | dst = append(dst, src[start:i]...) |
| | } |
| | dst = append(dst, '\\', 'u', '2', '0', '2', hex[src[i+2]&0xF]) |
| | start = i + 3 |
| | } |
| | v := scan.step(scan, c) |
| | if v >= scanSkipSpace { |
| | if v == scanError { |
| | break |
| | } |
| | if start < i { |
| | dst = append(dst, src[start:i]...) |
| | } |
| | start = i + 1 |
| | } |
| | } |
| | if scan.eof() == scanError { |
| | return dst[:origLen], scan.err |
| | } |
| | if start < len(src) { |
| | dst = append(dst, src[start:]...) |
| | } |
| | return dst, nil |
| | } |
| |
|
| | func appendNewline(dst []byte, prefix, indent string, depth int) []byte { |
| | dst = append(dst, '\n') |
| | dst = append(dst, prefix...) |
| | for i := 0; i < depth; i++ { |
| | dst = append(dst, indent...) |
| | } |
| | return dst |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | const indentGrowthFactor = 2 |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { |
| | dst.Grow(indentGrowthFactor * len(src)) |
| | b := dst.AvailableBuffer() |
| | b, err := appendIndent(b, src, prefix, indent) |
| | dst.Write(b) |
| | return err |
| | } |
| |
|
| | func appendIndent(dst, src []byte, prefix, indent string) ([]byte, error) { |
| | origLen := len(dst) |
| | scan := newScanner() |
| | defer freeScanner(scan) |
| | needIndent := false |
| | depth := 0 |
| | for _, c := range src { |
| | scan.bytes++ |
| | v := scan.step(scan, c) |
| | if v == scanSkipSpace { |
| | continue |
| | } |
| | if v == scanError { |
| | break |
| | } |
| | if needIndent && v != scanEndObject && v != scanEndArray { |
| | needIndent = false |
| | depth++ |
| | dst = appendNewline(dst, prefix, indent, depth) |
| | } |
| |
|
| | |
| | |
| | if v == scanContinue { |
| | dst = append(dst, c) |
| | continue |
| | } |
| |
|
| | |
| | switch c { |
| | case '{', '[': |
| | |
| | needIndent = true |
| | dst = append(dst, c) |
| | case ',': |
| | dst = append(dst, c) |
| | dst = appendNewline(dst, prefix, indent, depth) |
| | case ':': |
| | dst = append(dst, c, ' ') |
| | case '}', ']': |
| | if needIndent { |
| | |
| | needIndent = false |
| | } else { |
| | depth-- |
| | dst = appendNewline(dst, prefix, indent, depth) |
| | } |
| | dst = append(dst, c) |
| | default: |
| | dst = append(dst, c) |
| | } |
| | } |
| | if scan.eof() == scanError { |
| | return dst[:origLen], scan.err |
| | } |
| | return dst, nil |
| | } |
| |
|