mirror of
https://github.com/golang/go
synced 2024-10-04 22:31:22 -06:00
3cfa2c3ddf
This is the first of probably four separate CLs for the new implementation of the json package. The scanner is the core of the new implementation. The other CLs would be the new decoder, the new encoder, and support for JSON streams. R=r CC=golang-dev https://golang.org/cl/802051
117 lines
2.5 KiB
Go
117 lines
2.5 KiB
Go
// Copyright 2010 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package json
|
|
|
|
import (
|
|
"bytes"
|
|
"os"
|
|
)
|
|
|
|
// Compact appends to dst the JSON-encoded src with
|
|
// insignificant space characters elided.
|
|
func Compact(dst *bytes.Buffer, src []byte) os.Error {
|
|
origLen := dst.Len()
|
|
var scan scanner
|
|
scan.reset()
|
|
start := 0
|
|
for i, c := range src {
|
|
v := scan.step(&scan, int(c))
|
|
if v >= scanSkipSpace {
|
|
if v == scanError {
|
|
break
|
|
}
|
|
if start < i {
|
|
dst.Write(src[start:i])
|
|
}
|
|
start = i + 1
|
|
}
|
|
}
|
|
if scan.eof() == scanError {
|
|
dst.Truncate(origLen)
|
|
return scan.err
|
|
}
|
|
if start < len(src) {
|
|
dst.Write(src[start:])
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
|
|
dst.WriteByte('\n')
|
|
dst.WriteString(prefix)
|
|
for i := 0; i < depth; i++ {
|
|
dst.WriteString(indent)
|
|
}
|
|
}
|
|
|
|
// Indent appends to dst an indented form of the JSON-encoded src.
|
|
// Each element in a JSON object or array begins on a new,
|
|
// indented line beginning with prefix followed by one or more
|
|
// copies of indent according to the indentation nesting.
|
|
// The data appended to dst has no trailing newline, to make it easier
|
|
// to embed inside other formatted JSON data.
|
|
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) os.Error {
|
|
origLen := dst.Len()
|
|
var scan scanner
|
|
scan.reset()
|
|
needIndent := false
|
|
depth := 0
|
|
for _, c := range src {
|
|
v := scan.step(&scan, int(c))
|
|
if v == scanSkipSpace {
|
|
continue
|
|
}
|
|
if v == scanError {
|
|
break
|
|
}
|
|
if needIndent && v != scanEndObject && v != scanEndArray {
|
|
needIndent = false
|
|
depth++
|
|
newline(dst, prefix, indent, depth)
|
|
}
|
|
|
|
// Emit semantically uninteresting bytes
|
|
// (in particular, punctuation in strings) unmodified.
|
|
if v == scanContinue {
|
|
dst.WriteByte(c)
|
|
continue
|
|
}
|
|
|
|
// Add spacing around real punctuation.
|
|
switch c {
|
|
case '{', '[':
|
|
// delay indent so that empty object and array are formatted as {} and [].
|
|
needIndent = true
|
|
dst.WriteByte(c)
|
|
|
|
case ',':
|
|
dst.WriteByte(c)
|
|
newline(dst, prefix, indent, depth)
|
|
|
|
case ':':
|
|
dst.WriteByte(c)
|
|
dst.WriteByte(' ')
|
|
|
|
case '}', ']':
|
|
if needIndent {
|
|
// suppress indent in empty object/array
|
|
needIndent = false
|
|
} else {
|
|
depth--
|
|
newline(dst, prefix, indent, depth)
|
|
}
|
|
dst.WriteByte(c)
|
|
|
|
default:
|
|
dst.WriteByte(c)
|
|
}
|
|
}
|
|
if scan.eof() == scanError {
|
|
dst.Truncate(origLen)
|
|
return scan.err
|
|
}
|
|
return nil
|
|
}
|