spec_compat.go raw

   1  // +build !amd64,!arm64 go1.25 !go1.16 arm64,!go1.20
   2  
   3  /**
   4   * Copyright 2024 ByteDance Inc.
   5   *
   6   * Licensed under the Apache License, Version 2.0 (the "License");
   7   * you may not use this file except in compliance with the License.
   8   * You may obtain a copy of the License at
   9   *
  10   *     http://www.apache.org/licenses/LICENSE-2.0
  11   *
  12   * Unless required by applicable law or agreed to in writing, software
  13   * distributed under the License is distributed on an "AS IS" BASIS,
  14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15   * See the License for the specific language governing permissions and
  16   * limitations under the License.
  17   */
  18  
  19  package alg
  20  
  21  import (
  22  	_ "unsafe"
  23  	"unicode/utf8"
  24  	"strconv"
  25  	"bytes"
  26  	"encoding/json"
  27  
  28  	"github.com/bytedance/sonic/internal/rt"
  29  )
  30  
  31  // Valid validates json and returns first non-blank character position,
  32  // if it is only one valid json value.
  33  // Otherwise returns invalid character position using start.
  34  //
  35  // Note: it does not check for the invalid UTF-8 characters.
  36  func Valid(data []byte) (ok bool, start int) {
  37  	ok = json.Valid(data)
  38  	return ok, 0
  39  }
  40  
  41  var typeByte = rt.UnpackEface(byte(0)).Type
  42  
  43  func Quote(e []byte, s string, double bool) []byte {
  44  	if len(s) == 0 {
  45  		if double {
  46  			return append(e, `"\"\""`...)
  47  		}
  48  		return append(e, `""`...)
  49  	}
  50  
  51  	b := e
  52  	ss := len(e)
  53  	e = append(e, '"')
  54  	start := 0
  55  
  56  	for i := 0; i < len(s); {
  57  		if b := s[i]; b < utf8.RuneSelf {
  58  			if rt.SafeSet[b] {
  59  				i++
  60  				continue
  61  			}
  62  			if start < i {
  63  				e = append(e, s[start:i]...)
  64  			}
  65  			e = append(e, '\\')
  66  			switch b {
  67  			case '\\', '"':
  68  				e = append(e, b)
  69  			case '\n':
  70  				e = append(e, 'n')
  71  			case '\r':
  72  				e = append(e, 'r')
  73  			case '\t':
  74  				e = append(e, 't')
  75  			default:
  76  				// This encodes bytes < 0x20 except for \t, \n and \r.
  77  				// If escapeHTML is set, it also escapes <, >, and &
  78  				// because they can lead to security holes when
  79  				// user-controlled strings are rendered into JSON
  80  				// and served to some browsers.
  81  				e = append(e, `u00`...)
  82  				e = append(e, rt.Hex[b>>4])
  83  				e = append(e, rt.Hex[b&0xF])
  84  			}
  85  			i++
  86  			start = i
  87  			continue
  88  		}
  89  		c, size := utf8.DecodeRuneInString(s[i:])
  90  		// if correct && c == utf8.RuneError && size == 1 {
  91  		// 	if start < i {
  92  		// 		e = append(e, s[start:i]...)
  93  		// 	}
  94  		// 	e = append(e, `\ufffd`...)
  95  		// 	i += size
  96  		// 	start = i
  97  		// 	continue
  98  		// }
  99  		if c == '\u2028' || c == '\u2029' {
 100  			if start < i {
 101  				e = append(e, s[start:i]...)
 102  			}
 103  			e = append(e, `\u202`...)
 104  			e = append(e, rt.Hex[c&0xF])
 105  			i += size
 106  			start = i
 107  			continue
 108  		}
 109  		i += size
 110  	}
 111  
 112  	if start < len(s) {
 113  		e = append(e, s[start:]...)
 114  	}
 115  	e = append(e, '"')
 116  
 117  	if double {
 118  		return strconv.AppendQuote(b, string(e[ss:]))
 119  	} else {
 120  		return e
 121  	}
 122  }
 123  
 124  func HtmlEscape(dst []byte, src []byte) []byte {
 125  	buf := bytes.NewBuffer(dst)
 126  	json.HTMLEscape(buf, src)
 127  	return buf.Bytes()
 128  }
 129  
 130  func F64toa(buf []byte, v float64) ([]byte) {
 131  	bs := bytes.NewBuffer(buf)
 132  	_ = json.NewEncoder(bs).Encode(v)
 133  	return bs.Bytes()
 134  }
 135  
 136  func F32toa(buf []byte, v float32) ([]byte) {
 137  	bs := bytes.NewBuffer(buf)
 138  	_ = json.NewEncoder(bs).Encode(v)
 139  	return bs.Bytes()
 140  }
 141  
 142  func I64toa(buf []byte, v int64) ([]byte) {
 143  	return strconv.AppendInt(buf, int64(v), 10)
 144  }
 145  
 146  func U64toa(buf []byte, v uint64) ([]byte) {
 147  	return strconv.AppendUint(buf, v, 10)
 148  }
 149