1// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// author xeipuuv 16// author-github https://github.com/xeipuuv 17// author-mail xeipuuv@gmail.com 18// 19// repository-name gojsonschema 20// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. 21// 22// description Various utility functions. 23// 24// created 26-02-2013 25 26package gojsonschema 27 28import ( 29 "encoding/json" 30 "math/big" 31 "reflect" 32) 33 34func isKind(what interface{}, kinds ...reflect.Kind) bool { 35 target := what 36 if isJSONNumber(what) { 37 // JSON Numbers are strings! 38 target = *mustBeNumber(what) 39 } 40 targetKind := reflect.ValueOf(target).Kind() 41 for _, kind := range kinds { 42 if targetKind == kind { 43 return true 44 } 45 } 46 return false 47} 48 49func existsMapKey(m map[string]interface{}, k string) bool { 50 _, ok := m[k] 51 return ok 52} 53 54func isStringInSlice(s []string, what string) bool { 55 for i := range s { 56 if s[i] == what { 57 return true 58 } 59 } 60 return false 61} 62 63// indexStringInSlice returns the index of the first instance of 'what' in s or -1 if it is not found in s. 64func indexStringInSlice(s []string, what string) int { 65 for i := range s { 66 if s[i] == what { 67 return i 68 } 69 } 70 return -1 71} 72 73func marshalToJSONString(value interface{}) (*string, error) { 74 75 mBytes, err := json.Marshal(value) 76 if err != nil { 77 return nil, err 78 } 79 80 sBytes := string(mBytes) 81 return &sBytes, nil 82} 83 84func marshalWithoutNumber(value interface{}) (*string, error) { 85 86 // The JSON is decoded using https://golang.org/pkg/encoding/json/#Decoder.UseNumber 87 // This means the numbers are internally still represented as strings and therefore 1.00 is unequal to 1 88 // One way to eliminate these differences is to decode and encode the JSON one more time without Decoder.UseNumber 89 // so that these differences in representation are removed 90 91 jsonString, err := marshalToJSONString(value) 92 if err != nil { 93 return nil, err 94 } 95 96 var document interface{} 97 98 err = json.Unmarshal([]byte(*jsonString), &document) 99 if err != nil { 100 return nil, err 101 } 102 103 return marshalToJSONString(document) 104} 105 106func isJSONNumber(what interface{}) bool { 107 108 switch what.(type) { 109 110 case json.Number: 111 return true 112 } 113 114 return false 115} 116 117func checkJSONInteger(what interface{}) (isInt bool) { 118 119 jsonNumber := what.(json.Number) 120 121 bigFloat, isValidNumber := new(big.Rat).SetString(string(jsonNumber)) 122 123 return isValidNumber && bigFloat.IsInt() 124 125} 126 127// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 128const ( 129 maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1 130 minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1 131) 132 133func mustBeInteger(what interface{}) *int { 134 135 if isJSONNumber(what) { 136 137 number := what.(json.Number) 138 139 isInt := checkJSONInteger(number) 140 141 if isInt { 142 143 int64Value, err := number.Int64() 144 if err != nil { 145 return nil 146 } 147 148 int32Value := int(int64Value) 149 return &int32Value 150 } 151 152 } 153 154 return nil 155} 156 157func mustBeNumber(what interface{}) *big.Rat { 158 159 if isJSONNumber(what) { 160 number := what.(json.Number) 161 float64Value, success := new(big.Rat).SetString(string(number)) 162 if success { 163 return float64Value 164 } 165 } 166 167 return nil 168 169} 170 171func convertDocumentNode(val interface{}) interface{} { 172 173 if lval, ok := val.([]interface{}); ok { 174 175 res := []interface{}{} 176 for _, v := range lval { 177 res = append(res, convertDocumentNode(v)) 178 } 179 180 return res 181 182 } 183 184 if mval, ok := val.(map[interface{}]interface{}); ok { 185 186 res := map[string]interface{}{} 187 188 for k, v := range mval { 189 res[k.(string)] = convertDocumentNode(v) 190 } 191 192 return res 193 194 } 195 196 return val 197} 198