package filter import ( "smesh.lol/pkg/lol/errorf" ) func skipJSONValue(b []byte) (val []byte, r []byte, err error) { if len(b) == 0 { err = errorf.E([]byte("empty input")) return } start := 0 end := 0 switch b[0] { case '{': end, err = findMatchingBrace(b, '{', '}') case '[': end, err = findMatchingBrace(b, '[', ']') case '"': end, err = findClosingQuote(b) case 't': if len(b) >= 4 && string(b[:4]) == "true" { end = 4 } else { err = errorf.E([]byte("invalid JSON value starting with 't'")) } case 'f': if len(b) >= 5 && string(b[:5]) == "false" { end = 5 } else { err = errorf.E([]byte("invalid JSON value starting with 'f'")) } case 'n': if len(b) >= 4 && string(b[:4]) == "null" { end = 4 } else { err = errorf.E([]byte("invalid JSON value starting with 'n'")) } case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': end = scanNumber(b) default: err = errorf.E([]byte("invalid JSON value starting with '%c'"), b[0]) } if err != nil { return } val = b[start:end] r = b[end:] return } func findMatchingBrace(b []byte, open, close byte) (end int, err error) { if len(b) == 0 || b[0] != open { err = errorf.E([]byte("expected '%c'"), open) return } depth := 0 inString := false escaped := false for i := 0; i < len(b); i++ { c := b[i] if escaped { escaped = false continue } if c == '\\' && inString { escaped = true continue } if c == '"' { inString = !inString continue } if inString { continue } if c == open { depth++ } else if c == close { depth-- if depth == 0 { end = i + 1 return } } } err = errorf.E([]byte("unmatched '%c'"), open) return } func findClosingQuote(b []byte) (end int, err error) { if len(b) == 0 || b[0] != '"' { err = errorf.E([]byte("expected '\"'")) return } escaped := false for i := 1; i < len(b); i++ { c := b[i] if escaped { escaped = false continue } if c == '\\' { escaped = true continue } if c == '"' { end = i + 1 return } } err = errorf.E([]byte("unclosed string")) return } func scanNumber(b []byte) (end int) { for i := 0; i < len(b); i++ { c := b[i] if (c >= '0' && c <= '9') || c == '-' || c == '+' || c == '.' || c == 'e' || c == 'E' { continue } end = i return } end = len(b) return }