github.com/vanus-labs/vanus/lib@v0.0.0-20231221070800-1334a7b9605e/json/generate/string.go (about)

     1  // Copyright 2023 Linkall Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Inspired by https://github.com/ohler55/ojg/blob/9a6023ee37455ae9a61af3368f0635a2fabd2021/string.go
    16  
    17  package generate
    18  
    19  import (
    20  	// standard libraries.
    21  	"unicode/utf8"
    22  
    23  	// this project.
    24  	"github.com/vanus-labs/vanus/lib/bytes"
    25  )
    26  
    27  const (
    28  	hex = "0123456789abcdef"
    29  
    30  	hioff  = 4
    31  	himask = 0xf0
    32  	lomask = 0x0f
    33  )
    34  
    35  const basicPlan = "" +
    36  	`........btn.fr..................` + // 0x00
    37  	`oo"ooooooooooooooooooooooooooooo` + // 0x20
    38  	`oooooooooooooooooooooooooooo\ooo` + // 0x40
    39  	`ooooooooooooooooooooooooooooooo.` + // 0x60
    40  	`88888888888888888888888888888888` + // 0x80
    41  	`88888888888888888888888888888888` + // 0xa0
    42  	`88888888888888888888888888888888` + // 0xc0
    43  	`88888888888888888888888888888888` //  0xe0
    44  
    45  const htmlSafePlan = "" + //nolint:unused // reserved for future use.
    46  	`........btn.fr..................` + // 0x00
    47  	`oo"ooo.ooooooooooooooooooooo.o.o` + // 0x20
    48  	`oooooooooooooooooooooooooooo\ooo` + // 0x40
    49  	`ooooooooooooooooooooooooooooooo.` + // 0x60
    50  	`88888888888888888888888888888888` + // 0x80
    51  	`88888888888888888888888888888888` + // 0xa0
    52  	`88888888888888888888888888888888` + // 0xc0
    53  	`88888888888888888888888888888888` //  0xe0
    54  
    55  // AppendString appends a JSON encoding of a string to the provided byte slice.
    56  func AppendString(dst []byte, s string) []byte {
    57  	dst = append(dst, '"')
    58  	dst = AppendRawString(dst, s)
    59  	return append(dst, '"')
    60  }
    61  
    62  func AppendRawString(dst []byte, s string) []byte {
    63  	return appendRawString(dst, bytes.UnsafeFromString(s), basicPlan)
    64  }
    65  
    66  func appendRawString(dst []byte, bs []byte, plan string) []byte {
    67  	var i, start int
    68  
    69  	lazyAppend := func() {
    70  		if start >= i {
    71  			return
    72  		}
    73  		s := bytes.UnsafeSlice(bs, start, i)
    74  		dst = append(dst, s...)
    75  	}
    76  	advance := func(n int) {
    77  		i += n
    78  	}
    79  	next := func(n int) {
    80  		advance(n)
    81  		start = i
    82  	}
    83  
    84  	n := len(bs)
    85  	for i < n {
    86  		c := bytes.UnsafeAt(bs, i)
    87  		p := bytes.UnsafeAt(plan, int(c))
    88  		switch p {
    89  		case 'o':
    90  			advance(1)
    91  		case '.':
    92  			lazyAppend()
    93  			dst = AppendByteAsUnicode(dst, c)
    94  			next(1)
    95  		case '8':
    96  			s := bytes.UnsafeSlice(bs, i, n)
    97  			r, cnt := utf8.DecodeRune(s)
    98  			switch r {
    99  			case '\u2028':
   100  				lazyAppend()
   101  				dst = append(dst, `\u2028`...)
   102  				next(cnt)
   103  			case '\u2029':
   104  				lazyAppend()
   105  				dst = append(dst, `\u2029`...)
   106  				next(cnt)
   107  			case utf8.RuneError:
   108  				lazyAppend()
   109  				dst = append(dst, `\ufffd`...)
   110  				next(cnt)
   111  			default:
   112  				advance(cnt)
   113  			}
   114  		default:
   115  			lazyAppend()
   116  			dst = append(dst, '\\', p)
   117  			next(1)
   118  		}
   119  	}
   120  
   121  	i = n // maybe unnecessary?
   122  	lazyAppend()
   123  
   124  	return dst
   125  }
   126  
   127  func AppendByteAsUnicode(dst []byte, b byte) []byte {
   128  	return append(dst, '\\', 'u', '0', '0', hex[(b>>hioff)&lomask], hex[b&lomask])
   129  }