github.com/zerosnake0/jzon@v0.0.9-0.20230801092939-1b135cb83f7f/streamer_str.go (about) 1 package jzon 2 3 import ( 4 "unicode/utf8" 5 ) 6 7 var ( 8 hex = "0123456789abcdef" 9 safeSet = [utf8.RuneSelf]string{ 10 // < ' ' 11 '\n': `\n`, 12 '\r': `\r`, 13 '\t': `\t`, 14 // >= ' ' 15 '"': `\"`, 16 '\\': `\\`, 17 } 18 htmlSafeSet = [utf8.RuneSelf]string{ 19 // < ' ' 20 '\n': `\n`, 21 '\r': `\r`, 22 '\t': `\t`, 23 // >= ' ' 24 '"': `\"`, 25 '\\': `\\`, 26 '<': `\u003c`, 27 '>': `\u003e`, 28 '&': `\u0026`, 29 } 30 ) 31 32 func (s *Streamer) String(str string) *Streamer { 33 if s.Error != nil { 34 return s 35 } 36 s.onVal() 37 s.buffer = encodeString(s.buffer, str, s.safeSet) 38 return s 39 } 40 41 func encodeString(buffer []byte, str string, safeSet []string) []byte { 42 buffer = append(buffer, '"') // leading quote 43 l := len(str) 44 offset := 0 45 i := 0 46 for i < l { 47 c := str[i] 48 if c < utf8.RuneSelf { 49 if c >= ' ' { 50 if hs := safeSet[c]; hs != "" { 51 buffer = append(buffer, str[offset:i]...) 52 buffer = append(buffer, hs...) 53 i++ 54 offset = i 55 } else { 56 i++ 57 } 58 } else { 59 buffer = append(buffer, str[offset:i]...) 60 if hs := htmlSafeSet[c]; hs != "" { 61 buffer = append(buffer, hs...) 62 } else { 63 buffer = append(buffer, '\\', 'u', '0', '0', 64 hex[c>>4], hex[c&0xF]) 65 } 66 i++ 67 offset = i 68 } 69 } else { // c >= 0x80 70 r, size := utf8.DecodeRuneInString(str[i:]) 71 if r == utf8.RuneError && size == 1 { 72 buffer = append(buffer, str[offset:i]...) 73 buffer = append(buffer, '\\', 'u', 74 'f', 'f', 'f', 'd') 75 i++ 76 offset = i 77 continue 78 } 79 80 if r == '\u2028' || r == '\u2029' { 81 buffer = append(buffer, str[offset:i]...) 82 buffer = append(buffer, '\\', 'u', 83 '2', '0', '2', hex[r&0xF]) 84 i += size 85 offset = i 86 } else { 87 i += size 88 } 89 } 90 } 91 buffer = append(buffer, str[offset:i]...) 92 buffer = append(buffer, '"') // trailing quote 93 return buffer 94 }