github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/msgfmt/formatter_bytes.go (about) 1 package msgfmt 2 3 import "unicode/utf8" 4 5 type bytesFormatter int 6 7 func (formatter bytesFormatter) Format(space []byte, properties []interface{}) []byte { 8 return writeBytes(space, properties[formatter].([]byte)) 9 } 10 11 // safeSet holds the value true if the ASCII character with the given array 12 // position can be represented inside a JSON string without any further 13 // escaping. 14 // 15 // All values are true except for the ASCII control characters (0-31), the 16 // double quote ("), and the backslash character ("\"). 17 var safeSet = [utf8.RuneSelf]bool{ 18 ' ': true, 19 '!': true, 20 '"': true, 21 '#': true, 22 '$': true, 23 '%': true, 24 '&': true, 25 '\'': true, 26 '(': true, 27 ')': true, 28 '*': true, 29 '+': true, 30 ',': true, 31 '-': true, 32 '.': true, 33 '/': true, 34 '0': true, 35 '1': true, 36 '2': true, 37 '3': true, 38 '4': true, 39 '5': true, 40 '6': true, 41 '7': true, 42 '8': true, 43 '9': true, 44 ':': true, 45 ';': true, 46 '<': true, 47 '=': true, 48 '>': true, 49 '?': true, 50 '@': true, 51 'A': true, 52 'B': true, 53 'C': true, 54 'D': true, 55 'E': true, 56 'F': true, 57 'G': true, 58 'H': true, 59 'I': true, 60 'J': true, 61 'K': true, 62 'L': true, 63 'M': true, 64 'N': true, 65 'O': true, 66 'P': true, 67 'Q': true, 68 'R': true, 69 'S': true, 70 'T': true, 71 'U': true, 72 'V': true, 73 'W': true, 74 'X': true, 75 'Y': true, 76 'Z': true, 77 '[': true, 78 '\\': false, 79 ']': true, 80 '^': true, 81 '_': true, 82 '`': true, 83 'a': true, 84 'b': true, 85 'c': true, 86 'd': true, 87 'e': true, 88 'f': true, 89 'g': true, 90 'h': true, 91 'i': true, 92 'j': true, 93 'k': true, 94 'l': true, 95 'm': true, 96 'n': true, 97 'o': true, 98 'p': true, 99 'q': true, 100 'r': true, 101 's': true, 102 't': true, 103 'u': true, 104 'v': true, 105 'w': true, 106 'x': true, 107 'y': true, 108 'z': true, 109 '{': true, 110 '|': false, 111 '}': true, 112 '~': true, 113 '\u007f': true, 114 } 115 116 var hex = "0123456789abcdef" 117 118 func writeBytes(space []byte, s []byte) []byte { 119 // write string, the fast path, without utf8 and escape support 120 var i int 121 var c byte 122 for i, c = range s { 123 if c < utf8.RuneSelf && safeSet[c] { 124 space = append(space, c) 125 } else { 126 break 127 } 128 } 129 if i == len(s)-1 { 130 return space 131 } 132 return writeBytesSlowPath(space, s[i:]) 133 } 134 135 func writeBytesSlowPath(space []byte, s []byte) []byte { 136 start := 0 137 // for the remaining parts, we process them char by char 138 var i int 139 var b byte 140 for i, b = range s { 141 if b >= utf8.RuneSelf { 142 space = append(space, '\\', 'x', hex[b>>4], hex[b&0xF]) 143 start = i + 1 144 continue 145 } 146 if safeSet[b] { 147 continue 148 } 149 if start < i { 150 space = append(space, s[start:i]...) 151 } 152 switch b { 153 case '\\', '"': 154 space = append(space, '\\', b) 155 case '\n': 156 space = append(space, '\\', 'n') 157 case '\r': 158 space = append(space, '\\', 'r') 159 case '\t': 160 space = append(space, '\\', 't') 161 default: 162 // This encodes bytes < 0x20 except for \t, \n and \r. 163 space = append(space, '\\', 'x', hex[b>>4], hex[b&0xF]) 164 } 165 start = i + 1 166 } 167 if start < len(s) { 168 space = append(space, s[start:]...) 169 } 170 return space 171 }