package jsoncommentstrip
import (
"bufio"
"io"
)
type state int
const (
stateNormal state = iota
stateInString
stateInStringEscape
stateMaybeComment
stateLineComment
stateBlockComment
stateMaybeBlockEnd
)
type reader struct {
r *bufio.Reader
state state
}
func NewReader(r io.Reader) io.Reader {
return &reader{
r: bufio.NewReader(r),
state: stateNormal,
}
}
func (cr *reader) Read(p []byte) (int, error) {
n := 0
for n < len(p) {
b, err := cr.r.ReadByte()
if err != nil {
if cr.state == stateMaybeComment {
p[n] = '/'
n++
cr.state = stateNormal
}
return n, err
}
switch cr.state {
case stateNormal:
switch b {
case '"':
p[n] = b
n++
cr.state = stateInString
case '/':
cr.state = stateMaybeComment
default:
p[n] = b
n++
}
case stateInString:
p[n] = b
n++
switch b {
case '\\':
cr.state = stateInStringEscape
case '"':
cr.state = stateNormal
}
case stateInStringEscape:
p[n] = b
n++
cr.state = stateInString
case stateMaybeComment:
switch b {
case '/':
cr.state = stateLineComment
case '*':
cr.state = stateBlockComment
default:
p[n] = '/'
n++
if n < len(p) {
p[n] = b
n++
} else {
_ = cr.r.UnreadByte()
}
cr.state = stateNormal
}
case stateLineComment:
if b == '\n' || b == '\r' {
p[n] = b
n++
cr.state = stateNormal
}
case stateBlockComment:
if b == '*' {
cr.state = stateMaybeBlockEnd
}
case stateMaybeBlockEnd:
if b == '/' {
cr.state = stateNormal
} else if b == '*' {
cr.state = stateMaybeBlockEnd
} else {
cr.state = stateBlockComment
}
}
}
return n, nil
}