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  }