202 lines
4.8 KiB
Go
202 lines
4.8 KiB
Go
package jsonvalue
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/Andrew-M-C/go.jsonvalue/internal/buffer"
|
|
)
|
|
|
|
func formatBool(b bool) string {
|
|
if b {
|
|
return "true"
|
|
}
|
|
return "false"
|
|
}
|
|
|
|
// reference:
|
|
// - [UTF-16](https://zh.wikipedia.org/zh-cn/UTF-16)
|
|
// - [JavaScript has a Unicode problem](https://mathiasbynens.be/notes/javascript-unicode)
|
|
// - [Meaning of escaped unicode characters in JSON](https://stackoverflow.com/questions/21995410/meaning-of-escaped-unicode-characters-in-json)
|
|
func escapeGreaterUnicodeToBuffByUTF16(r rune, buf buffer.Buffer) {
|
|
if r <= '\uffff' {
|
|
_, _ = buf.WriteString(fmt.Sprintf("\\u%04X", r))
|
|
return
|
|
}
|
|
// if r > 0x10FFFF {
|
|
// // invalid unicode
|
|
// buf.WriteRune(r)
|
|
// return
|
|
// }
|
|
|
|
r = r - 0x10000
|
|
lo := r & 0x003FF
|
|
hi := (r & 0xFFC00) >> 10
|
|
_, _ = buf.WriteString(fmt.Sprintf("\\u%04X", hi+0xD800))
|
|
_, _ = buf.WriteString(fmt.Sprintf("\\u%04X", lo+0xDC00))
|
|
}
|
|
|
|
func escapeGreaterUnicodeToBuffByUTF8(r rune, buf buffer.Buffer) {
|
|
// Comments below are copied from encoding/json:
|
|
//
|
|
// U+2028 is LINE SEPARATOR.
|
|
// U+2029 is PARAGRAPH SEPARATOR.
|
|
// They are both technically valid characters in JSON strings,
|
|
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
|
// and can lead to security holes there. It is valid JSON to
|
|
// escape them, so we do so unconditionally.
|
|
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
|
if r == '\u2028' || r == '\u2029' {
|
|
escapeGreaterUnicodeToBuffByUTF16(r, buf)
|
|
} else {
|
|
_, _ = buf.WriteRune(r)
|
|
}
|
|
}
|
|
|
|
func escapeNothing(b byte, buf buffer.Buffer) {
|
|
_ = buf.WriteByte(b)
|
|
}
|
|
|
|
func escAsciiControlChar(b byte, buf buffer.Buffer) {
|
|
upper := b >> 4
|
|
lower := b & 0x0F
|
|
|
|
writeChar := func(c byte) {
|
|
if c < 0xA {
|
|
_ = buf.WriteByte('0' + c)
|
|
} else {
|
|
_ = buf.WriteByte('A' + (c - 0xA))
|
|
}
|
|
}
|
|
|
|
_, _ = buf.Write([]byte{'\\', 'u', '0', '0'})
|
|
writeChar(upper)
|
|
writeChar(lower)
|
|
}
|
|
|
|
func escDoubleQuote(_ byte, buf buffer.Buffer) {
|
|
_, _ = buf.Write([]byte{'\\', '"'})
|
|
}
|
|
|
|
func escSlash(_ byte, buf buffer.Buffer) {
|
|
_, _ = buf.Write([]byte{'\\', '/'})
|
|
}
|
|
|
|
func escBackslash(_ byte, buf buffer.Buffer) {
|
|
_, _ = buf.Write([]byte{'\\', '\\'})
|
|
}
|
|
|
|
func escBackspace(_ byte, buf buffer.Buffer) {
|
|
_, _ = buf.Write([]byte{'\\', 'b'})
|
|
}
|
|
|
|
func escVertTab(_ byte, buf buffer.Buffer) {
|
|
_, _ = buf.Write([]byte{'\\', 'f'})
|
|
}
|
|
|
|
func escTab(_ byte, buf buffer.Buffer) {
|
|
_, _ = buf.Write([]byte{'\\', 't'})
|
|
}
|
|
|
|
func escNewLine(_ byte, buf buffer.Buffer) {
|
|
_, _ = buf.Write([]byte{'\\', 'n'})
|
|
}
|
|
|
|
func escReturn(_ byte, buf buffer.Buffer) {
|
|
_, _ = buf.Write([]byte{'\\', 'r'})
|
|
}
|
|
|
|
func escLeftAngle(_ byte, buf buffer.Buffer) {
|
|
_, _ = buf.Write([]byte{'\\', 'u', '0', '0', '3', 'C'})
|
|
}
|
|
|
|
func escRightAngle(_ byte, buf buffer.Buffer) {
|
|
_, _ = buf.Write([]byte{'\\', 'u', '0', '0', '3', 'E'})
|
|
}
|
|
|
|
func escAnd(_ byte, buf buffer.Buffer) {
|
|
_, _ = buf.Write([]byte{'\\', 'u', '0', '0', '2', '6'})
|
|
}
|
|
|
|
// func escPercent(_ byte, buf buffer.Buffer) {
|
|
// buf.Write([]byte{'\\', 'u', '0', '0', '2', '5'})
|
|
// }
|
|
|
|
func escapeStringToBuff(s string, buf buffer.Buffer, opt *Opt) {
|
|
for _, r := range s {
|
|
if r <= 0x7F {
|
|
b := byte(r)
|
|
opt.asciiCharEscapingFunc[b](b, buf)
|
|
} else {
|
|
opt.unicodeEscapingFunc(r, buf)
|
|
}
|
|
}
|
|
}
|
|
|
|
func anyToInt(v any) (u int, err error) {
|
|
if v == nil {
|
|
return 0, fmt.Errorf("%w: parameter is nil", ErrParameterError)
|
|
}
|
|
value := reflect.ValueOf(v)
|
|
switch value.Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return int(value.Int()), nil
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return int(value.Uint()), nil
|
|
default:
|
|
return 0, fmt.Errorf("%v is not a number", reflect.TypeOf(v))
|
|
}
|
|
}
|
|
|
|
func anyToString(v any) (s string, err error) {
|
|
if v == nil {
|
|
return "", fmt.Errorf("%w: parameter is nil", ErrParameterError)
|
|
}
|
|
rv := reflect.ValueOf(v)
|
|
if rv.Type().Kind() == reflect.String {
|
|
return rv.String(), nil
|
|
}
|
|
|
|
return "", fmt.Errorf("%w: %s is not a string", ErrParameterError, reflect.TypeOf(v).String())
|
|
}
|
|
|
|
func isSliceAndExtractDividedParams(p any) (ok bool, firstParam any, otherParams []any) {
|
|
v := reflect.ValueOf(p)
|
|
switch v.Kind() {
|
|
default:
|
|
return false, nil, nil
|
|
case reflect.Slice, reflect.Array:
|
|
// yes, go on
|
|
}
|
|
|
|
paramCount := v.Len()
|
|
if paramCount == 0 {
|
|
return true, nil, nil
|
|
}
|
|
|
|
firstParam = v.Index(0).Interface()
|
|
|
|
for i := 1; i < v.Len(); i++ {
|
|
element := v.Index(i)
|
|
otherParams = append(otherParams, element.Interface())
|
|
}
|
|
return true, firstParam, otherParams
|
|
}
|
|
|
|
func isSliceAndExtractJointParams(p any) (bool, []any) {
|
|
v := reflect.ValueOf(p)
|
|
switch v.Kind() {
|
|
default:
|
|
return false, nil
|
|
case reflect.Slice, reflect.Array:
|
|
// yes, go on
|
|
}
|
|
|
|
res := make([]any, 0, v.Len())
|
|
for i := 0; i < v.Len(); i++ {
|
|
element := v.Index(i)
|
|
res = append(res, element.Interface())
|
|
}
|
|
return true, res
|
|
}
|