json reader that allows comments

pull/330/head
Darien Raymond 8 years ago
parent 3b5a791ae8
commit b469dea315
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169

@ -0,0 +1,94 @@
package json
import (
"io"
)
type State byte
const (
StateContent State = 0
StateEscape State = 1
StateDoubleQuote State = 2
StateSingleQuote State = 3
StateComment State = 4
StateSlash State = 5
StateMultilineComment State = 6
StateMultilineCommentStar State = 7
)
type Reader struct {
io.Reader
state State
}
func (v *Reader) Read(b []byte) (int, error) {
n, err := v.Reader.Read(b)
if err != nil {
return n, err
}
p := b[:0]
for _, x := range b[:n] {
switch v.state {
case StateContent:
switch x {
case '"':
v.state = StateDoubleQuote
p = append(p, x)
case '\'':
v.state = StateSingleQuote
p = append(p, x)
case '\\':
v.state = StateEscape
case '#':
v.state = StateComment
case '/':
v.state = StateSlash
default:
p = append(p, x)
}
case StateEscape:
p = append(p, x)
v.state = StateContent
case StateDoubleQuote:
if x == '"' {
v.state = StateContent
}
p = append(p, x)
case StateSingleQuote:
if x == '\'' {
v.state = StateContent
}
p = append(p, x)
case StateComment:
if x == '\n' {
v.state = StateContent
}
case StateSlash:
switch x {
case '/':
v.state = StateComment
case '*':
v.state = StateMultilineComment
default:
p = append(p, '/', x)
}
case StateMultilineComment:
if x == '*' {
v.state = StateMultilineCommentStar
}
case StateMultilineCommentStar:
switch x {
case '/':
v.state = StateContent
case '*':
// Stay
default:
v.state = StateMultilineComment
}
default:
panic("Unknown state.")
}
}
return len(p), nil
}

@ -0,0 +1,47 @@
package json_test
import (
"testing"
"bytes"
"v2ray.com/core/testing/assert"
. "v2ray.com/core/tools/conf/json"
)
func TestReader(t *testing.T) {
assert := assert.On(t)
data := []struct {
input string
output string
}{
{
`
content #comment 1
#comment 2
content 2`,
`
content content 2`},
{`content`, `content`},
{" ", " "},
{`con/*abcd*/tent`, "content"},
{`
text // adlkhdf /*
//comment adfkj
text 2*/`, `
text text 2*`},
{`"//"content`, `"//"content`},
{`abcd'//'abcd`, `abcd'//'abcd`},
}
for _, testCase := range data {
reader := &Reader{
Reader: bytes.NewReader([]byte(testCase.input)),
}
actual := make([]byte, 1024)
n, err := reader.Read(actual)
assert.Error(err).IsNil()
assert.String(string(actual[:n])).Equals(testCase.output)
}
}

@ -8,6 +8,7 @@ import (
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
"v2ray.com/core/common/loader" "v2ray.com/core/common/loader"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
json_reader "v2ray.com/core/tools/conf/json"
) )
var ( var (
@ -337,7 +338,9 @@ func (v *Config) Build() (*core.Config, error) {
func init() { func init() {
core.RegisterConfigLoader(core.ConfigFormat_JSON, func(input io.Reader) (*core.Config, error) { core.RegisterConfigLoader(core.ConfigFormat_JSON, func(input io.Reader) (*core.Config, error) {
jsonConfig := &Config{} jsonConfig := &Config{}
decoder := json.NewDecoder(input) decoder := json.NewDecoder(&json_reader.Reader{
Reader: input,
})
err := decoder.Decode(jsonConfig) err := decoder.Decode(jsonConfig)
if err != nil { if err != nil {
return nil, errors.Base(err).Message("Invalid V2Ray config.") return nil, errors.Base(err).Message("Invalid V2Ray config.")

Loading…
Cancel
Save