Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / docker / go / canonical / json / indent.go
1 // Copyright 2010 The Go Authors.  All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package json
6
7 import "bytes"
8
9 // Compact appends to dst the JSON-encoded src with
10 // insignificant space characters elided.
11 func Compact(dst *bytes.Buffer, src []byte) error {
12         return compact(dst, src, false)
13 }
14
15 func compact(dst *bytes.Buffer, src []byte, escape bool) error {
16         origLen := dst.Len()
17         var scan scanner
18         scan.reset()
19         start := 0
20         for i, c := range src {
21                 if escape && (c == '<' || c == '>' || c == '&') {
22                         if start < i {
23                                 dst.Write(src[start:i])
24                         }
25                         dst.WriteString(`\u00`)
26                         dst.WriteByte(hex[c>>4])
27                         dst.WriteByte(hex[c&0xF])
28                         start = i + 1
29                 }
30                 // Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
31                 if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
32                         if start < i {
33                                 dst.Write(src[start:i])
34                         }
35                         dst.WriteString(`\u202`)
36                         dst.WriteByte(hex[src[i+2]&0xF])
37                         start = i + 3
38                 }
39                 v := scan.step(&scan, c)
40                 if v >= scanSkipSpace {
41                         if v == scanError {
42                                 break
43                         }
44                         if start < i {
45                                 dst.Write(src[start:i])
46                         }
47                         start = i + 1
48                 }
49         }
50         if scan.eof() == scanError {
51                 dst.Truncate(origLen)
52                 return scan.err
53         }
54         if start < len(src) {
55                 dst.Write(src[start:])
56         }
57         return nil
58 }
59
60 func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
61         dst.WriteByte('\n')
62         dst.WriteString(prefix)
63         for i := 0; i < depth; i++ {
64                 dst.WriteString(indent)
65         }
66 }
67
68 // Indent appends to dst an indented form of the JSON-encoded src.
69 // Each element in a JSON object or array begins on a new,
70 // indented line beginning with prefix followed by one or more
71 // copies of indent according to the indentation nesting.
72 // The data appended to dst does not begin with the prefix nor
73 // any indentation, to make it easier to embed inside other formatted JSON data.
74 // Although leading space characters (space, tab, carriage return, newline)
75 // at the beginning of src are dropped, trailing space characters
76 // at the end of src are preserved and copied to dst.
77 // For example, if src has no trailing spaces, neither will dst;
78 // if src ends in a trailing newline, so will dst.
79 func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
80         origLen := dst.Len()
81         var scan scanner
82         scan.reset()
83         needIndent := false
84         depth := 0
85         for _, c := range src {
86                 scan.bytes++
87                 v := scan.step(&scan, c)
88                 if v == scanSkipSpace {
89                         continue
90                 }
91                 if v == scanError {
92                         break
93                 }
94                 if needIndent && v != scanEndObject && v != scanEndArray {
95                         needIndent = false
96                         depth++
97                         newline(dst, prefix, indent, depth)
98                 }
99
100                 // Emit semantically uninteresting bytes
101                 // (in particular, punctuation in strings) unmodified.
102                 if v == scanContinue {
103                         dst.WriteByte(c)
104                         continue
105                 }
106
107                 // Add spacing around real punctuation.
108                 switch c {
109                 case '{', '[':
110                         // delay indent so that empty object and array are formatted as {} and [].
111                         needIndent = true
112                         dst.WriteByte(c)
113
114                 case ',':
115                         dst.WriteByte(c)
116                         newline(dst, prefix, indent, depth)
117
118                 case ':':
119                         dst.WriteByte(c)
120                         dst.WriteByte(' ')
121
122                 case '}', ']':
123                         if needIndent {
124                                 // suppress indent in empty object/array
125                                 needIndent = false
126                         } else {
127                                 depth--
128                                 newline(dst, prefix, indent, depth)
129                         }
130                         dst.WriteByte(c)
131
132                 default:
133                         dst.WriteByte(c)
134                 }
135         }
136         if scan.eof() == scanError {
137                 dst.Truncate(origLen)
138                 return scan.err
139         }
140         return nil
141 }