...
1 package cjson
2
3 import (
4 "bytes"
5 "encoding/json"
6 "errors"
7 "fmt"
8 "reflect"
9 "sort"
10 "strings"
11 )
12
13
20 func encodeCanonicalString(s string) string {
21
22 s = strings.ReplaceAll(s, "\\", "\\\\")
23
24 s = strings.ReplaceAll(s, "\"", "\\\"")
25
26 return fmt.Sprintf("\"%s\"", s)
27 }
28
29
35 func encodeCanonical(obj interface{}, result *strings.Builder) (err error) {
36 switch objAsserted := obj.(type) {
37 case string:
38 result.WriteString(encodeCanonicalString(objAsserted))
39
40 case bool:
41 if objAsserted {
42 result.WriteString("true")
43 } else {
44 result.WriteString("false")
45 }
46
47
48
49
50
51
52 case json.Number:
53 if _, err := objAsserted.Int64(); err != nil {
54 panic(fmt.Sprintf("Can't canonicalize floating point number '%s'",
55 objAsserted))
56 }
57 result.WriteString(objAsserted.String())
58
59 case nil:
60 result.WriteString("null")
61
62
63 case []interface{}:
64 result.WriteString("[")
65 for i, val := range objAsserted {
66 if err := encodeCanonical(val, result); err != nil {
67 return err
68 }
69 if i < (len(objAsserted) - 1) {
70 result.WriteString(",")
71 }
72 }
73 result.WriteString("]")
74
75 case map[string]interface{}:
76 result.WriteString("{")
77
78
79 var mapKeys []string
80 for key := range objAsserted {
81 mapKeys = append(mapKeys, key)
82 }
83
84 sort.Strings(mapKeys)
85
86
87 for i, key := range mapKeys {
88 if err := encodeCanonical(key, result); err != nil {
89 return err
90 }
91
92 result.WriteString(":")
93 if err := encodeCanonical(objAsserted[key], result); err != nil {
94 return err
95 }
96 if i < (len(mapKeys) - 1) {
97 result.WriteString(",")
98 }
99 i++
100 }
101 result.WriteString("}")
102
103 default:
104
105 panic(fmt.Sprintf("Can't canonicalize '%s' of type '%s'",
106 objAsserted, reflect.TypeOf(objAsserted)))
107 }
108 return nil
109 }
110
111
117 func EncodeCanonical(obj interface{}) (out []byte, err error) {
118
119
120
121 defer func() {
122 if r := recover(); r != nil {
123 err = errors.New(r.(string))
124 }
125 }()
126
127
128
129 data, err := json.Marshal(obj)
130 if err != nil {
131 return nil, err
132 }
133 var jsonMap interface{}
134
135 dec := json.NewDecoder(bytes.NewReader(data))
136 dec.UseNumber()
137 if err := dec.Decode(&jsonMap); err != nil {
138 return nil, err
139 }
140
141
142 var result strings.Builder
143
144 result.Grow(len(data))
145
146 if err := encodeCanonical(jsonMap, &result); err != nil {
147 return nil, err
148 }
149
150 return []byte(result.String()), nil
151 }
152
View as plain text