Initial commit

This commit is contained in:
eleksir
2025-05-08 18:12:52 +03:00
commit cff1b6811f
1596 changed files with 659567 additions and 0 deletions

0
vendor/github.com/hjson/hjson-go/.gitignore generated vendored Normal file
View File

21
vendor/github.com/hjson/hjson-go/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016, 2017 Christian Zangl
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

181
vendor/github.com/hjson/hjson-go/README.md generated vendored Normal file
View File

@@ -0,0 +1,181 @@
# hjson-go
[![Build Status](https://github.com/hjson/hjson-go/workflows/test/badge.svg)](https://github.com/hjson/hjson-go/actions)
[![Go Pkg](https://img.shields.io/github/release/hjson/hjson-go.svg?style=flat-square&label=go-pkg)](https://github.com/hjson/hjson-go/releases)
[![Go Report Card](https://goreportcard.com/badge/github.com/hjson/hjson-go?style=flat-square)](https://goreportcard.com/report/github.com/hjson/hjson-go)
[![coverage](https://img.shields.io/badge/coverage-ok-brightgreen.svg?style=flat-square)](http://gocover.io/github.com/hjson/hjson-go/)
[![godoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/hjson/hjson-go)
![Hjson Intro](https://hjson.github.io/hjson1.gif)
```
{
# specify rate in requests/second (because comments are helpful!)
rate: 1000
// prefer c-style comments?
/* feeling old fashioned? */
# did you notice that rate doesn't need quotes?
hey: look ma, no quotes for strings either!
# best of all
notice: []
anything: ?
# yes, commas are optional!
}
```
The Go implementation of Hjson is based on [hjson-js](https://github.com/hjson/hjson-js). For other platforms see [hjson.github.io](https://hjson.github.io).
# Install
Make sure you have a working Go environment. See the [install instructions](http://golang.org/doc/install.html).
1. Get the sources
```bash
$ go get -u github.com/hjson/hjson-go
```
2. Build the **hjson-cli** commandline tool (optional)
```bash
$ cd $(go env GOPATH)/src/github.com/hjson/hjson-go/hjson-cli && go install
$ hjson-cli --version
```
# Usage as command line tool
```
usage: hjson-cli [OPTIONS] [INPUT]
hjson can be used to convert JSON from/to Hjson.
hjson will read the given JSON/Hjson input file or read from stdin.
Options:
-allowMinusZero
Allow -0.
-bracesSameLine
Print braces on the same line.
-c Output as JSON.
-h Show this screen.
-indentBy string
The indent string. (default " ")
-j Output as formatted JSON.
-omitRootBraces
Omit braces at the root.
-quoteAlways
Always quote string values.
```
Sample:
- run `hjson-cli test.json > test.hjson` to convert to Hjson
- run `hjson-cli -j test.hjson > test.json` to convert to JSON
# Usage as a GO library
```go
package main
import (
"github.com/hjson/hjson-go"
"fmt"
)
func main() {
// Now let's look at decoding Hjson data into Go
// values.
sampleText := []byte(`
{
# specify rate in requests/second
rate: 1000
array:
[
foo
bar
]
}`)
// We need to provide a variable where Hjson
// can put the decoded data.
var dat map[string]interface{}
// Decode and a check for errors.
if err := hjson.Unmarshal(sampleText, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
// In order to use the values in the decoded map,
// we'll need to cast them to their appropriate type.
rate := dat["rate"].(float64)
fmt.Println(rate)
array := dat["array"].([]interface{})
str1 := array[0].(string)
fmt.Println(str1)
// To encode to Hjson with default options:
sampleMap := map[string]int{"apple": 5, "lettuce": 7}
hjson, _ := hjson.Marshal(sampleMap)
// this is short for:
// options := hjson.DefaultOptions()
// hjson, _ := hjson.MarshalWithOptions(sampleMap, options)
fmt.Println(string(hjson))
}
```
If you prefer, you can also unmarshal to Go objects by converting to JSON:
```go
package main
import (
"github.com/hjson/hjson-go"
"encoding/json"
"fmt"
)
type Sample struct {
Rate int
Array []string
}
func main() {
sampleText := []byte(`
{
# specify rate in requests/second
rate: 1000
array:
[
foo
bar
]
}`)
// read Hjson
var dat map[string]interface{}
hjson.Unmarshal(sampleText, &dat)
// convert to JSON
b, _ := json.Marshal(dat)
// unmarshal
var sample Sample
json.Unmarshal(b, &sample)
fmt.Println(sample.Rate)
fmt.Println(sample.Array)
}
```
# API
[![godoc](https://godoc.org/github.com/hjson/hjson-go?status.svg)](http://godoc.org/github.com/hjson/hjson-go)
# History
[see releases](https://github.com/hjson/hjson-go/releases)

58
vendor/github.com/hjson/hjson-go/build_release.sh generated vendored Normal file
View File

@@ -0,0 +1,58 @@
#!/bin/bash
cd `dirname $0`
ROOT=$PWD/_dist
if [ -d "$ROOT" ]; then rm -rf $ROOT; fi
mkdir $ROOT
function build() {
export GOOS=$1
export GOARCH=$2
echo build $GOOS $GOARCH
OUT=$ROOT/${GOOS}_${GOARCH}
mkdir $OUT
cd $OUT
go build github.com/hjson/hjson-go/hjson-cli
if [[ $3 == "zip" ]]; then
mv $OUT/hjson-cli.exe $OUT/hjson.exe
zip -j ${OUT}.zip $OUT/*
else
mv $OUT/hjson-cli $OUT/hjson
tar -czf ${OUT}.tar.gz -C $OUT .
fi
}
# not all targets can be built on travis
# build android arm
build darwin 386
build darwin amd64
# build darwin arm
# build darwin arm64
build dragonfly amd64
build freebsd 386
build freebsd amd64
build freebsd arm
build linux 386
build linux amd64
build linux arm
build linux arm64
build linux mips64
build linux mips64le
build linux ppc64
build linux ppc64le
build netbsd 386
build netbsd amd64
build netbsd arm
build openbsd 386
build openbsd amd64
build openbsd arm
build plan9 386
build plan9 amd64
build solaris amd64
build windows 386 zip
build windows amd64 zip

480
vendor/github.com/hjson/hjson-go/decode.go generated vendored Normal file
View File

@@ -0,0 +1,480 @@
package hjson
import (
"bytes"
"fmt"
"reflect"
"strings"
)
type hjsonParser struct {
data []byte
at int // The index of the current character
ch byte // The current character
}
func (p *hjsonParser) resetAt() {
p.at = 0
p.ch = ' '
}
func isPunctuatorChar(c byte) bool {
return c == '{' || c == '}' || c == '[' || c == ']' || c == ',' || c == ':'
}
func (p *hjsonParser) errAt(message string) error {
var i int
col := 0
line := 1
for i = p.at - 1; i > 0 && p.data[i] != '\n'; i-- {
col++
}
for ; i > 0; i-- {
if p.data[i] == '\n' {
line++
}
}
samEnd := p.at - col + 20
if samEnd > len(p.data) {
samEnd = len(p.data)
}
return fmt.Errorf("%s at line %d,%d >>> %s", message, line, col, string(p.data[p.at-col:samEnd]))
}
func (p *hjsonParser) next() bool {
// get the next character.
if p.at < len(p.data) {
p.ch = p.data[p.at]
p.at++
return true
}
p.ch = 0
return false
}
func (p *hjsonParser) peek(offs int) byte {
pos := p.at + offs
if pos >= 0 && pos < len(p.data) {
return p.data[p.at+offs]
}
return 0
}
var escapee = map[byte]byte{
'"': '"',
'\'': '\'',
'\\': '\\',
'/': '/',
'b': '\b',
'f': '\f',
'n': '\n',
'r': '\r',
't': '\t',
}
func (p *hjsonParser) readString(allowML bool) (string, error) {
// Parse a string value.
res := new(bytes.Buffer)
// callers make sure that (ch === '"' || ch === "'")
// When parsing for string values, we must look for " and \ characters.
exitCh := p.ch
for p.next() {
if p.ch == exitCh {
p.next()
if allowML && exitCh == '\'' && p.ch == '\'' && res.Len() == 0 {
// ''' indicates a multiline string
p.next()
return p.readMLString()
} else {
return res.String(), nil
}
}
if p.ch == '\\' {
p.next()
if p.ch == 'u' {
uffff := 0
for i := 0; i < 4; i++ {
p.next()
var hex int
if p.ch >= '0' && p.ch <= '9' {
hex = int(p.ch - '0')
} else if p.ch >= 'a' && p.ch <= 'f' {
hex = int(p.ch - 'a' + 0xa)
} else if p.ch >= 'A' && p.ch <= 'F' {
hex = int(p.ch - 'A' + 0xa)
} else {
return "", p.errAt("Bad \\u char " + string(p.ch))
}
uffff = uffff*16 + hex
}
res.WriteRune(rune(uffff))
} else if ech, ok := escapee[p.ch]; ok {
res.WriteByte(ech)
} else {
return "", p.errAt("Bad escape \\" + string(p.ch))
}
} else if p.ch == '\n' || p.ch == '\r' {
return "", p.errAt("Bad string containing newline")
} else {
res.WriteByte(p.ch)
}
}
return "", p.errAt("Bad string")
}
func (p *hjsonParser) readMLString() (value string, err error) {
// Parse a multiline string value.
res := new(bytes.Buffer)
triple := 0
// we are at ''' +1 - get indent
indent := 0
for {
c := p.peek(-indent - 5)
if c == 0 || c == '\n' {
break
}
indent++
}
skipIndent := func() {
skip := indent
for p.ch > 0 && p.ch <= ' ' && p.ch != '\n' && skip > 0 {
skip--
p.next()
}
}
// skip white/to (newline)
for p.ch > 0 && p.ch <= ' ' && p.ch != '\n' {
p.next()
}
if p.ch == '\n' {
p.next()
skipIndent()
}
// When parsing multiline string values, we must look for ' characters.
lastLf := false
for {
if p.ch == 0 {
return "", p.errAt("Bad multiline string")
} else if p.ch == '\'' {
triple++
p.next()
if triple == 3 {
sres := res.Bytes()
if lastLf {
return string(sres[0 : len(sres)-1]), nil // remove last EOL
}
return string(sres), nil
}
continue
} else {
for triple > 0 {
res.WriteByte('\'')
triple--
lastLf = false
}
}
if p.ch == '\n' {
res.WriteByte('\n')
lastLf = true
p.next()
skipIndent()
} else {
if p.ch != '\r' {
res.WriteByte(p.ch)
lastLf = false
}
p.next()
}
}
}
func (p *hjsonParser) readKeyname() (string, error) {
// quotes for keys are optional in Hjson
// unless they include {}[],: or whitespace.
if p.ch == '"' || p.ch == '\'' {
return p.readString(false)
}
name := new(bytes.Buffer)
start := p.at
space := -1
for {
if p.ch == ':' {
if name.Len() == 0 {
return "", p.errAt("Found ':' but no key name (for an empty key name use quotes)")
} else if space >= 0 && space != name.Len() {
p.at = start + space
return "", p.errAt("Found whitespace in your key name (use quotes to include)")
}
return name.String(), nil
} else if p.ch <= ' ' {
if p.ch == 0 {
return "", p.errAt("Found EOF while looking for a key name (check your syntax)")
}
if space < 0 {
space = name.Len()
}
} else {
if isPunctuatorChar(p.ch) {
return "", p.errAt("Found '" + string(p.ch) + "' where a key name was expected (check your syntax or use quotes if the key name includes {}[],: or whitespace)")
}
name.WriteByte(p.ch)
}
p.next()
}
}
func (p *hjsonParser) white() {
for p.ch > 0 {
// Skip whitespace.
for p.ch > 0 && p.ch <= ' ' {
p.next()
}
// Hjson allows comments
if p.ch == '#' || p.ch == '/' && p.peek(0) == '/' {
for p.ch > 0 && p.ch != '\n' {
p.next()
}
} else if p.ch == '/' && p.peek(0) == '*' {
p.next()
p.next()
for p.ch > 0 && !(p.ch == '*' && p.peek(0) == '/') {
p.next()
}
if p.ch > 0 {
p.next()
p.next()
}
} else {
break
}
}
}
func (p *hjsonParser) readTfnns() (interface{}, error) {
// Hjson strings can be quoteless
// returns string, true, false, or null.
if isPunctuatorChar(p.ch) {
return nil, p.errAt("Found a punctuator character '" + string(p.ch) + "' when expecting a quoteless string (check your syntax)")
}
chf := p.ch
value := new(bytes.Buffer)
value.WriteByte(p.ch)
for {
p.next()
isEol := p.ch == '\r' || p.ch == '\n' || p.ch == 0
if isEol ||
p.ch == ',' || p.ch == '}' || p.ch == ']' ||
p.ch == '#' ||
p.ch == '/' && (p.peek(0) == '/' || p.peek(0) == '*') {
switch chf {
case 'f':
if strings.TrimSpace(value.String()) == "false" {
return false, nil
}
case 'n':
if strings.TrimSpace(value.String()) == "null" {
return nil, nil
}
case 't':
if strings.TrimSpace(value.String()) == "true" {
return true, nil
}
default:
if chf == '-' || chf >= '0' && chf <= '9' {
if n, err := tryParseNumber(value.Bytes(), false); err == nil {
return n, nil
}
}
}
if isEol {
// remove any whitespace at the end (ignored in quoteless strings)
return strings.TrimSpace(value.String()), nil
}
}
value.WriteByte(p.ch)
}
}
func (p *hjsonParser) readArray() (value interface{}, err error) {
// Parse an array value.
// assuming ch == '['
array := make([]interface{}, 0, 1)
p.next()
p.white()
if p.ch == ']' {
p.next()
return array, nil // empty array
}
for p.ch > 0 {
var val interface{}
if val, err = p.readValue(); err != nil {
return nil, err
}
array = append(array, val)
p.white()
// in Hjson the comma is optional and trailing commas are allowed
if p.ch == ',' {
p.next()
p.white()
}
if p.ch == ']' {
p.next()
return array, nil
}
p.white()
}
return nil, p.errAt("End of input while parsing an array (did you forget a closing ']'?)")
}
func (p *hjsonParser) readObject(withoutBraces bool) (value interface{}, err error) {
// Parse an object value.
object := make(map[string]interface{})
if !withoutBraces {
// assuming ch == '{'
p.next()
}
p.white()
if p.ch == '}' && !withoutBraces {
p.next()
return object, nil // empty object
}
for p.ch > 0 {
var key string
if key, err = p.readKeyname(); err != nil {
return nil, err
}
p.white()
if p.ch != ':' {
return nil, p.errAt("Expected ':' instead of '" + string(p.ch) + "'")
}
p.next()
// duplicate keys overwrite the previous value
var val interface{}
if val, err = p.readValue(); err != nil {
return nil, err
}
object[key] = val
p.white()
// in Hjson the comma is optional and trailing commas are allowed
if p.ch == ',' {
p.next()
p.white()
}
if p.ch == '}' && !withoutBraces {
p.next()
return object, nil
}
p.white()
}
if withoutBraces {
return object, nil
}
return nil, p.errAt("End of input while parsing an object (did you forget a closing '}'?)")
}
func (p *hjsonParser) readValue() (interface{}, error) {
// Parse a Hjson value. It could be an object, an array, a string, a number or a word.
p.white()
switch p.ch {
case '{':
return p.readObject(false)
case '[':
return p.readArray()
case '"', '\'':
return p.readString(true)
default:
return p.readTfnns()
}
}
func (p *hjsonParser) rootValue() (interface{}, error) {
// Braces for the root object are optional
p.white()
switch p.ch {
case '{':
return p.checkTrailing(p.readObject(false))
case '[':
return p.checkTrailing(p.readArray())
}
// assume we have a root object without braces
res, err := p.checkTrailing(p.readObject(true))
if err == nil {
return res, nil
}
// test if we are dealing with a single JSON value instead (true/false/null/num/"")
p.resetAt()
if res2, err2 := p.checkTrailing(p.readValue()); err2 == nil {
return res2, nil
}
return res, err
}
func (p *hjsonParser) checkTrailing(v interface{}, err error) (interface{}, error) {
if err != nil {
return nil, err
}
p.white()
if p.ch > 0 {
return nil, p.errAt("Syntax error, found trailing characters")
}
return v, nil
}
// Unmarshal parses the Hjson-encoded data and stores the result
// in the value pointed to by v.
//
// Unmarshal uses the inverse of the encodings that
// Marshal uses, allocating maps, slices, and pointers as necessary.
//
func Unmarshal(data []byte, v interface{}) (err error) {
var value interface{}
parser := &hjsonParser{data, 0, ' '}
parser.resetAt()
value, err = parser.rootValue()
if err != nil {
return err
}
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
return fmt.Errorf("non-pointer %v", reflect.TypeOf(v))
}
for rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
}
}()
rv.Set(reflect.ValueOf(value))
return err
}

492
vendor/github.com/hjson/hjson-go/encode.go generated vendored Normal file
View File

@@ -0,0 +1,492 @@
package hjson
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"math"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
"unicode/utf8"
)
// EncoderOptions defines options for encoding to Hjson.
type EncoderOptions struct {
// End of line, should be either \n or \r\n
Eol string
// Place braces on the same line
BracesSameLine bool
// Emit braces for the root object
EmitRootBraces bool
// Always place string in quotes
QuoteAlways bool
// Place string in quotes if it could otherwise be a number, boolean or null
QuoteAmbiguousStrings bool
// Indent string
IndentBy string
// Base indentation string
BaseIndentation string
// Allow the -0 value (unlike ES6)
AllowMinusZero bool
// Encode unknown values as 'null'
UnknownAsNull bool
}
// DefaultOptions returns the default encoding options.
func DefaultOptions() EncoderOptions {
opt := EncoderOptions{}
opt.Eol = "\n"
opt.BracesSameLine = false
opt.EmitRootBraces = true
opt.QuoteAlways = false
opt.QuoteAmbiguousStrings = true
opt.IndentBy = " "
opt.BaseIndentation = ""
opt.AllowMinusZero = false
opt.UnknownAsNull = false
return opt
}
type hjsonEncoder struct {
bytes.Buffer // output
EncoderOptions
indent int
}
var needsEscape, needsQuotes, needsEscapeML, startsWithKeyword, needsEscapeName *regexp.Regexp
func init() {
var commonRange = `\x7f-\x9f\x{00ad}\x{0600}-\x{0604}\x{070f}\x{17b4}\x{17b5}\x{200c}-\x{200f}\x{2028}-\x{202f}\x{2060}-\x{206f}\x{feff}\x{fff0}-\x{ffff}`
// needsEscape tests if the string can be written without escapes
needsEscape = regexp.MustCompile(`[\\\"\x00-\x1f` + commonRange + `]`)
// needsQuotes tests if the string can be written as a quoteless string (includes needsEscape but without \\ and \")
needsQuotes = regexp.MustCompile(`^\s|^"|^'|^#|^/\*|^//|^\{|^\}|^\[|^\]|^:|^,|\s$|[\x00-\x1f\x7f-\x9f\x{00ad}\x{0600}-\x{0604}\x{070f}\x{17b4}\x{17b5}\x{200c}-\x{200f}\x{2028}-\x{202f}\x{2060}-\x{206f}\x{feff}\x{fff0}-\x{ffff}]`)
// needsEscapeML tests if the string can be written as a multiline string (like needsEscape but without \n, \r, \\, \", \t)
var x08Or9 = `\x08` // `\x09` for the old behavior
needsEscapeML = regexp.MustCompile(`'''|^[\s]+$|[\x00-` + x08Or9 + `\x0b\x0c\x0e-\x1f` + commonRange + `]`)
// starts with a keyword and optionally is followed by a comment
startsWithKeyword = regexp.MustCompile(`^(true|false|null)\s*((,|\]|\}|#|//|/\*).*)?$`)
needsEscapeName = regexp.MustCompile(`[,\{\[\}\]\s:#"']|//|/\*`)
}
var meta = map[byte][]byte{
// table of character substitutions
'\b': []byte("\\b"),
'\t': []byte("\\t"),
'\n': []byte("\\n"),
'\f': []byte("\\f"),
'\r': []byte("\\r"),
'"': []byte("\\\""),
'\\': []byte("\\\\"),
}
func (e *hjsonEncoder) quoteReplace(text string) string {
return string(needsEscape.ReplaceAllFunc([]byte(text), func(a []byte) []byte {
c := meta[a[0]]
if c != nil {
return c
}
r, _ := utf8.DecodeRune(a)
return []byte(fmt.Sprintf("\\u%04x", r))
}))
}
func (e *hjsonEncoder) quote(value string, separator string, isRootObject bool) {
// Check if we can insert this string without quotes
// see hjson syntax (must not parse as true, false, null or number)
if len(value) == 0 {
e.WriteString(separator + `""`)
} else if e.QuoteAlways ||
needsQuotes.MatchString(value) || (e.QuoteAmbiguousStrings && (startsWithNumber([]byte(value)) ||
startsWithKeyword.MatchString(value))) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we first check if the string can be expressed in multiline
// format or we must replace the offending characters with safe escape
// sequences.
if !needsEscape.MatchString(value) {
e.WriteString(separator + `"` + value + `"`)
} else if !needsEscapeML.MatchString(value) && !isRootObject {
e.mlString(value, separator)
} else {
e.WriteString(separator + `"` + e.quoteReplace(value) + `"`)
}
} else {
// return without quotes
e.WriteString(separator + value)
}
}
func (e *hjsonEncoder) mlString(value string, separator string) {
// wrap the string into the ''' (multiline) format
a := strings.Split(strings.Replace(value, "\r", "", -1), "\n")
if len(a) == 1 {
// The string contains only a single line. We still use the multiline
// format as it avoids escaping the \ character (e.g. when used in a
// regex).
e.WriteString(separator + "'''")
e.WriteString(a[0])
} else {
e.writeIndent(e.indent + 1)
e.WriteString("'''")
for _, v := range a {
indent := e.indent + 1
if len(v) == 0 {
indent = 0
}
e.writeIndent(indent)
e.WriteString(v)
}
e.writeIndent(e.indent + 1)
}
e.WriteString("'''")
}
func (e *hjsonEncoder) quoteName(name string) string {
if len(name) == 0 {
return `""`
}
// Check if we can insert this name without quotes
if needsEscapeName.MatchString(name) {
if needsEscape.MatchString(name) {
name = e.quoteReplace(name)
}
return `"` + name + `"`
}
// without quotes
return name
}
type sortAlpha []reflect.Value
func (s sortAlpha) Len() int {
return len(s)
}
func (s sortAlpha) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s sortAlpha) Less(i, j int) bool {
return s[i].String() < s[j].String()
}
func (e *hjsonEncoder) writeIndent(indent int) {
e.WriteString(e.Eol)
e.WriteString(e.BaseIndentation)
for i := 0; i < indent; i++ {
e.WriteString(e.IndentBy)
}
}
func (e *hjsonEncoder) useMarshaler(value reflect.Value, separator string) error {
b, err := value.Interface().(json.Marshaler).MarshalJSON()
if err != nil {
return err
}
e.WriteString(separator)
e.WriteString(string(b))
return nil
}
var marshaler = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
func (e *hjsonEncoder) str(value reflect.Value, noIndent bool, separator string, isRootObject bool) error {
// Produce a string from value.
kind := value.Kind()
if kind == reflect.Interface || kind == reflect.Ptr {
if value.IsNil() {
e.WriteString(separator)
e.WriteString("null")
return nil
}
return e.str(value.Elem(),noIndent,separator,isRootObject)
}
if value.Type().Implements(marshaler) {
return e.useMarshaler(value, separator)
}
switch kind {
case reflect.String:
e.quote(value.String(), separator, isRootObject)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
e.WriteString(separator)
e.WriteString(strconv.FormatInt(value.Int(), 10))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Uintptr:
e.WriteString(separator)
e.WriteString(strconv.FormatUint(value.Uint(), 10))
case reflect.Float32, reflect.Float64:
// JSON numbers must be finite. Encode non-finite numbers as null.
e.WriteString(separator)
number := value.Float()
if math.IsInf(number, 0) || math.IsNaN(number) {
e.WriteString("null")
} else if !e.AllowMinusZero && number == -0 {
e.WriteString("0")
} else {
// find shortest representation ('G' does not work)
val := strconv.FormatFloat(number, 'f', -1, 64)
exp := strconv.FormatFloat(number, 'E', -1, 64)
if len(exp) < len(val) {
val = strings.ToLower(exp)
}
e.WriteString(val)
}
case reflect.Bool:
e.WriteString(separator)
if value.Bool() {
e.WriteString("true")
} else {
e.WriteString("false")
}
case reflect.Slice, reflect.Array:
len := value.Len()
if len == 0 {
e.WriteString(separator)
e.WriteString("[]")
break
}
indent1 := e.indent
e.indent++
if !noIndent && !e.BracesSameLine {
e.writeIndent(indent1)
} else {
e.WriteString(separator)
}
e.WriteString("[")
// Join all of the element texts together, separated with newlines
for i := 0; i < len; i++ {
e.writeIndent(e.indent)
if err := e.str(value.Index(i), true, "", false); err != nil {
return err
}
}
e.writeIndent(indent1)
e.WriteString("]")
e.indent = indent1
case reflect.Map:
len := value.Len()
if len == 0 {
e.WriteString(separator)
e.WriteString("{}")
break
}
indent1 := e.indent
if !isRootObject || e.EmitRootBraces {
if !noIndent && !e.BracesSameLine {
e.writeIndent(e.indent)
} else {
e.WriteString(separator)
}
e.indent++
e.WriteString("{")
}
keys := value.MapKeys()
sort.Sort(sortAlpha(keys))
// Join all of the member texts together, separated with newlines
for i := 0; i < len; i++ {
if i > 0 || !isRootObject || e.EmitRootBraces {
e.writeIndent(e.indent)
}
e.WriteString(e.quoteName(keys[i].String()))
e.WriteString(":")
if err := e.str(value.MapIndex(keys[i]), false, " ", false); err != nil {
return err
}
}
if !isRootObject || e.EmitRootBraces {
e.writeIndent(indent1)
e.WriteString("}")
}
e.indent = indent1
case reflect.Struct:
l := value.NumField()
if l == 0 {
e.WriteString(separator)
e.WriteString("{}")
break
}
indent1 := e.indent
if !isRootObject || e.EmitRootBraces {
if !noIndent && !e.BracesSameLine {
e.writeIndent(e.indent)
} else {
e.WriteString(separator)
}
e.indent++
e.WriteString("{")
}
// Join all of the member texts together, separated with newlines
for i := 0; i < l; i++ {
curStructField := value.Type().Field(i)
curField := value.Field(i)
name := curStructField.Name
jsonTag := curStructField.Tag.Get("json")
jsonComment := curStructField.Tag.Get("comment")
omitEmpty := false
if jsonTag == "-" {
continue
}
splits := strings.Split(jsonTag, ",")
if splits[0] != "" {
name = splits[0]
}
if len(splits) > 1 {
for _, opt := range splits[1:] {
if opt == "omitempty" {
omitEmpty = true
}
}
}
if omitEmpty && isEmptyValue(curField) {
continue
}
if len(jsonComment) > 0 {
for _, line := range strings.Split(jsonComment, e.Eol) {
if i > 0 || !isRootObject || e.EmitRootBraces {
e.writeIndent(e.indent)
}
e.WriteString(fmt.Sprintf("# %s", line))
}
}
if i > 0 || !isRootObject || e.EmitRootBraces {
e.writeIndent(e.indent)
}
e.WriteString(e.quoteName(name))
e.WriteString(":")
if err := e.str(curField, false, " ", false); err != nil {
return err
}
if len(jsonComment) > 0 && i < l-1 {
e.WriteString(e.Eol)
}
}
if !isRootObject || e.EmitRootBraces {
e.writeIndent(indent1)
e.WriteString("}")
}
e.indent = indent1
default:
if e.UnknownAsNull {
// Use null as a placeholder for non-JSON values.
e.WriteString("null")
} else {
return errors.New("Unsupported type " + value.Type().String())
}
}
return nil
}
func isEmptyValue(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
default:
return false
}
}
// Marshal returns the Hjson encoding of v using
// default options.
//
// See MarshalWithOptions.
//
func Marshal(v interface{}) ([]byte, error) {
return MarshalWithOptions(v, DefaultOptions())
}
// MarshalWithOptions returns the Hjson encoding of v.
//
// Marshal traverses the value v recursively.
//
// Boolean values encode as JSON booleans.
//
// Floating point, integer, and Number values encode as JSON numbers.
//
// String values encode as Hjson strings (quoteless, multiline or
// JSON).
//
// Array and slice values encode as JSON arrays.
//
// Map values encode as JSON objects. The map's key type must be a
// string. The map keys are sorted and used as JSON object keys.
//
// Pointer values encode as the value pointed to.
// A nil pointer encodes as the null JSON value.
//
// Interface values encode as the value contained in the interface.
// A nil interface value encodes as the null JSON value.
//
// JSON cannot represent cyclic data structures and Marshal does not
// handle them. Passing cyclic structures to Marshal will result in
// an infinite recursion.
//
func MarshalWithOptions(v interface{}, options EncoderOptions) ([]byte, error) {
e := &hjsonEncoder{}
e.indent = 0
e.Eol = options.Eol
e.BracesSameLine = options.BracesSameLine
e.EmitRootBraces = options.EmitRootBraces
e.QuoteAlways = options.QuoteAlways
e.QuoteAmbiguousStrings = options.QuoteAmbiguousStrings
e.IndentBy = options.IndentBy
e.BaseIndentation = options.BaseIndentation
err := e.str(reflect.ValueOf(v), true, e.BaseIndentation, true)
if err != nil {
return nil, err
}
return e.Bytes(), nil
}

108
vendor/github.com/hjson/hjson-go/parseNumber.go generated vendored Normal file
View File

@@ -0,0 +1,108 @@
package hjson
import (
"errors"
"math"
"strconv"
)
type parseNumber struct {
data []byte
at int // The index of the current character
ch byte // The current character
}
func (p *parseNumber) next() bool {
// get the next character.
len := len(p.data)
if p.at < len {
p.ch = p.data[p.at]
p.at++
return true
}
if p.at == len {
p.at++
p.ch = 0
}
return false
}
func (p *parseNumber) peek(offs int) byte {
pos := p.at + offs
if pos >= 0 && pos < len(p.data) {
return p.data[pos]
}
return 0
}
func startsWithNumber(text []byte) bool {
if _, err := tryParseNumber(text, true); err == nil {
return true
}
return false
}
func tryParseNumber(text []byte, stopAtNext bool) (float64, error) {
// Parse a number value.
p := parseNumber{text, 0, ' '}
leadingZeros := 0
testLeading := true
p.next()
if p.ch == '-' {
p.next()
}
for p.ch >= '0' && p.ch <= '9' {
if testLeading {
if p.ch == '0' {
leadingZeros++
} else {
testLeading = false
}
}
p.next()
}
if testLeading {
leadingZeros--
} // single 0 is allowed
if p.ch == '.' {
for p.next() && p.ch >= '0' && p.ch <= '9' {
}
}
if p.ch == 'e' || p.ch == 'E' {
p.next()
if p.ch == '-' || p.ch == '+' {
p.next()
}
for p.ch >= '0' && p.ch <= '9' {
p.next()
}
}
end := p.at
// skip white/to (newline)
for p.ch > 0 && p.ch <= ' ' {
p.next()
}
if stopAtNext {
// end scan if we find a punctuator character like ,}] or a comment
if p.ch == ',' || p.ch == '}' || p.ch == ']' ||
p.ch == '#' || p.ch == '/' && (p.peek(0) == '/' || p.peek(0) == '*') {
p.ch = 0
}
}
if p.ch > 0 || leadingZeros != 0 {
return 0, errors.New("Invalid number")
}
number, err := strconv.ParseFloat(string(p.data[0:end-1]), 64)
if err != nil {
return 0, err
}
if math.IsInf(number, 0) || math.IsNaN(number) {
return 0, errors.New("Invalid number")
}
return number, nil
}