Forráskód Böngészése

json reader that allows comments

Darien Raymond 9 éve
szülő
commit
b469dea315
3 módosított fájl, 145 hozzáadás és 1 törlés
  1. 94 0
      tools/conf/json/reader.go
  2. 47 0
      tools/conf/json/reader_test.go
  3. 4 1
      tools/conf/v2ray.go

+ 94 - 0
tools/conf/json/reader.go

@@ -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
+}

+ 47 - 0
tools/conf/json/reader_test.go

@@ -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)
+	}
+}

+ 4 - 1
tools/conf/v2ray.go

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