skip.mx raw

   1  package filter
   2  
   3  import (
   4  	"smesh.lol/pkg/lol/errorf"
   5  )
   6  
   7  func skipJSONValue(b []byte) (val []byte, r []byte, err error) {
   8  	if len(b) == 0 {
   9  		err = errorf.E([]byte("empty input"))
  10  		return
  11  	}
  12  	start := 0
  13  	end := 0
  14  	switch b[0] {
  15  	case '{':
  16  		end, err = findMatchingBrace(b, '{', '}')
  17  	case '[':
  18  		end, err = findMatchingBrace(b, '[', ']')
  19  	case '"':
  20  		end, err = findClosingQuote(b)
  21  	case 't':
  22  		if len(b) >= 4 && string(b[:4]) == "true" {
  23  			end = 4
  24  		} else {
  25  			err = errorf.E([]byte("invalid JSON value starting with 't'"))
  26  		}
  27  	case 'f':
  28  		if len(b) >= 5 && string(b[:5]) == "false" {
  29  			end = 5
  30  		} else {
  31  			err = errorf.E([]byte("invalid JSON value starting with 'f'"))
  32  		}
  33  	case 'n':
  34  		if len(b) >= 4 && string(b[:4]) == "null" {
  35  			end = 4
  36  		} else {
  37  			err = errorf.E([]byte("invalid JSON value starting with 'n'"))
  38  		}
  39  	case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
  40  		end = scanNumber(b)
  41  	default:
  42  		err = errorf.E([]byte("invalid JSON value starting with '%c'"), b[0])
  43  	}
  44  	if err != nil {
  45  		return
  46  	}
  47  	val = b[start:end]
  48  	r = b[end:]
  49  	return
  50  }
  51  
  52  func findMatchingBrace(b []byte, open, close byte) (end int, err error) {
  53  	if len(b) == 0 || b[0] != open {
  54  		err = errorf.E([]byte("expected '%c'"), open)
  55  		return
  56  	}
  57  	depth := 0
  58  	inString := false
  59  	escaped := false
  60  	for i := 0; i < len(b); i++ {
  61  		c := b[i]
  62  		if escaped {
  63  			escaped = false
  64  			continue
  65  		}
  66  		if c == '\\' && inString {
  67  			escaped = true
  68  			continue
  69  		}
  70  		if c == '"' {
  71  			inString = !inString
  72  			continue
  73  		}
  74  		if inString {
  75  			continue
  76  		}
  77  		if c == open {
  78  			depth++
  79  		} else if c == close {
  80  			depth--
  81  			if depth == 0 {
  82  				end = i + 1
  83  				return
  84  			}
  85  		}
  86  	}
  87  	err = errorf.E([]byte("unmatched '%c'"), open)
  88  	return
  89  }
  90  
  91  func findClosingQuote(b []byte) (end int, err error) {
  92  	if len(b) == 0 || b[0] != '"' {
  93  		err = errorf.E([]byte("expected '\"'"))
  94  		return
  95  	}
  96  	escaped := false
  97  	for i := 1; i < len(b); i++ {
  98  		c := b[i]
  99  		if escaped {
 100  			escaped = false
 101  			continue
 102  		}
 103  		if c == '\\' {
 104  			escaped = true
 105  			continue
 106  		}
 107  		if c == '"' {
 108  			end = i + 1
 109  			return
 110  		}
 111  	}
 112  	err = errorf.E([]byte("unclosed string"))
 113  	return
 114  }
 115  
 116  func scanNumber(b []byte) (end int) {
 117  	for i := 0; i < len(b); i++ {
 118  		c := b[i]
 119  		if (c >= '0' && c <= '9') || c == '-' || c == '+' || c == '.' || c == 'e' || c == 'E' {
 120  			continue
 121  		}
 122  		end = i
 123  		return
 124  	}
 125  	end = len(b)
 126  	return
 127  }
 128