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 }