github.com/sagernet/sing@v0.4.0-beta.19.0.20240518125136-f67a0988a636/common/json/comment.go (about)

     1  package json
     2  
     3  import (
     4  	"bufio"
     5  	"io"
     6  )
     7  
     8  // kanged from v2ray
     9  
    10  type commentFilterState = byte
    11  
    12  const (
    13  	commentFilterStateContent commentFilterState = iota
    14  	commentFilterStateEscape
    15  	commentFilterStateDoubleQuote
    16  	commentFilterStateDoubleQuoteEscape
    17  	commentFilterStateSingleQuote
    18  	commentFilterStateSingleQuoteEscape
    19  	commentFilterStateComment
    20  	commentFilterStateSlash
    21  	commentFilterStateMultilineComment
    22  	commentFilterStateMultilineCommentStar
    23  )
    24  
    25  type CommentFilter struct {
    26  	br    *bufio.Reader
    27  	state commentFilterState
    28  }
    29  
    30  func NewCommentFilter(reader io.Reader) io.Reader {
    31  	return &CommentFilter{br: bufio.NewReader(reader)}
    32  }
    33  
    34  func (v *CommentFilter) Read(b []byte) (int, error) {
    35  	p := b[:0]
    36  	for len(p) < len(b)-2 {
    37  		x, err := v.br.ReadByte()
    38  		if err != nil {
    39  			if len(p) == 0 {
    40  				return 0, err
    41  			}
    42  			return len(p), nil
    43  		}
    44  		switch v.state {
    45  		case commentFilterStateContent:
    46  			switch x {
    47  			case '"':
    48  				v.state = commentFilterStateDoubleQuote
    49  				p = append(p, x)
    50  			case '\'':
    51  				v.state = commentFilterStateSingleQuote
    52  				p = append(p, x)
    53  			case '\\':
    54  				v.state = commentFilterStateEscape
    55  			case '#':
    56  				v.state = commentFilterStateComment
    57  			case '/':
    58  				v.state = commentFilterStateSlash
    59  			default:
    60  				p = append(p, x)
    61  			}
    62  		case commentFilterStateEscape:
    63  			p = append(p, '\\', x)
    64  			v.state = commentFilterStateContent
    65  		case commentFilterStateDoubleQuote:
    66  			switch x {
    67  			case '"':
    68  				v.state = commentFilterStateContent
    69  				p = append(p, x)
    70  			case '\\':
    71  				v.state = commentFilterStateDoubleQuoteEscape
    72  			default:
    73  				p = append(p, x)
    74  			}
    75  		case commentFilterStateDoubleQuoteEscape:
    76  			p = append(p, '\\', x)
    77  			v.state = commentFilterStateDoubleQuote
    78  		case commentFilterStateSingleQuote:
    79  			switch x {
    80  			case '\'':
    81  				v.state = commentFilterStateContent
    82  				p = append(p, x)
    83  			case '\\':
    84  				v.state = commentFilterStateSingleQuoteEscape
    85  			default:
    86  				p = append(p, x)
    87  			}
    88  		case commentFilterStateSingleQuoteEscape:
    89  			p = append(p, '\\', x)
    90  			v.state = commentFilterStateSingleQuote
    91  		case commentFilterStateComment:
    92  			if x == '\n' {
    93  				v.state = commentFilterStateContent
    94  				p = append(p, '\n')
    95  			}
    96  		case commentFilterStateSlash:
    97  			switch x {
    98  			case '/':
    99  				v.state = commentFilterStateComment
   100  			case '*':
   101  				v.state = commentFilterStateMultilineComment
   102  			default:
   103  				p = append(p, '/', x)
   104  			}
   105  		case commentFilterStateMultilineComment:
   106  			switch x {
   107  			case '*':
   108  				v.state = commentFilterStateMultilineCommentStar
   109  			case '\n':
   110  				p = append(p, '\n')
   111  			}
   112  		case commentFilterStateMultilineCommentStar:
   113  			switch x {
   114  			case '/':
   115  				v.state = commentFilterStateContent
   116  			case '*':
   117  				// Stay
   118  			case '\n':
   119  				p = append(p, '\n')
   120  			default:
   121  				v.state = commentFilterStateMultilineComment
   122  			}
   123  		default:
   124  			panic("Unknown state.")
   125  		}
   126  	}
   127  	return len(p), nil
   128  }