github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/infra/conf/json/reader.go (about)

     1  package json
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/v2fly/v2ray-core/v5/common/buf"
     7  )
     8  
     9  // State is the internal state of parser.
    10  type State byte
    11  
    12  const (
    13  	StateContent State = iota
    14  	StateEscape
    15  	StateDoubleQuote
    16  	StateDoubleQuoteEscape
    17  	StateSingleQuote
    18  	StateSingleQuoteEscape
    19  	StateComment
    20  	StateSlash
    21  	StateMultilineComment
    22  	StateMultilineCommentStar
    23  )
    24  
    25  // Reader is a reader for filtering comments.
    26  // It supports Java style single and multi line comment syntax, and Python style single line comment syntax.
    27  type Reader struct {
    28  	io.Reader
    29  
    30  	state   State
    31  	pending []byte
    32  	br      *buf.BufferedReader
    33  }
    34  
    35  // Read implements io.Reader.Read().
    36  func (v *Reader) Read(b []byte) (int, error) {
    37  	if v.br == nil {
    38  		v.br = &buf.BufferedReader{Reader: buf.NewReader(v.Reader)}
    39  	}
    40  
    41  	p := b[:0]
    42  	for len(p) < len(b) {
    43  		if len(v.pending) > 0 {
    44  			max := len(b) - len(p)
    45  			if max > len(v.pending) {
    46  				max = len(v.pending)
    47  			}
    48  			p = append(p, v.pending[:max]...)
    49  			v.pending = v.pending[max:]
    50  			continue
    51  		}
    52  
    53  		x, err := v.br.ReadByte()
    54  		if err != nil {
    55  			if len(p) == 0 {
    56  				return 0, err
    57  			}
    58  			return len(p), nil
    59  		}
    60  		switch v.state {
    61  		case StateContent:
    62  			switch x {
    63  			case '"':
    64  				v.state = StateDoubleQuote
    65  				p = append(p, x)
    66  			case '\'':
    67  				v.state = StateSingleQuote
    68  				p = append(p, x)
    69  			case '\\':
    70  				v.state = StateEscape
    71  				p = append(p, x)
    72  			case '#':
    73  				v.state = StateComment
    74  			case '/':
    75  				v.state = StateSlash
    76  			default:
    77  				p = append(p, x)
    78  			}
    79  		case StateEscape:
    80  			p = append(p, x)
    81  			v.state = StateContent
    82  		case StateDoubleQuote:
    83  			switch x {
    84  			case '"':
    85  				v.state = StateContent
    86  				p = append(p, x)
    87  			case '\\':
    88  				v.state = StateDoubleQuoteEscape
    89  				p = append(p, x)
    90  			default:
    91  				p = append(p, x)
    92  			}
    93  		case StateDoubleQuoteEscape:
    94  			p = append(p, x)
    95  			v.state = StateDoubleQuote
    96  		case StateSingleQuote:
    97  			switch x {
    98  			case '\'':
    99  				v.state = StateContent
   100  				p = append(p, x)
   101  			case '\\':
   102  				v.state = StateSingleQuoteEscape
   103  				p = append(p, x)
   104  			default:
   105  				p = append(p, x)
   106  			}
   107  		case StateSingleQuoteEscape:
   108  			p = append(p, x)
   109  			v.state = StateSingleQuote
   110  		case StateComment:
   111  			if x == '\n' {
   112  				v.state = StateContent
   113  				p = append(p, x)
   114  			}
   115  		case StateSlash:
   116  			switch x {
   117  			case '/':
   118  				v.state = StateComment
   119  			case '*':
   120  				v.state = StateMultilineComment
   121  			default:
   122  				v.state = StateContent
   123  				v.pending = append(v.pending, x)
   124  				p = append(p, '/')
   125  			}
   126  		case StateMultilineComment:
   127  			switch x {
   128  			case '*':
   129  				v.state = StateMultilineCommentStar
   130  			case '\n':
   131  				p = append(p, x)
   132  			}
   133  		case StateMultilineCommentStar:
   134  			switch x {
   135  			case '/':
   136  				v.state = StateContent
   137  			case '*':
   138  				// Stay
   139  			case '\n':
   140  				p = append(p, x)
   141  			default:
   142  				v.state = StateMultilineComment
   143  			}
   144  		default:
   145  			panic("Unknown state.")
   146  		}
   147  	}
   148  	return len(p), nil
   149  }