package jsoniter import ( "fmt" "unicode/utf16" ) // ReadString read string from iterator func (iter *Iterator) ReadString() (ret string) { c := iter.nextToken() if c == '"' { for i := iter.head; i < iter.tail; i++ { c := iter.buf[i] if c == '"' { ret = string(iter.buf[iter.head:i]) iter.head = i + 1 return ret } else if c == '\\' { break } else if c < ' ' { iter.ReportError("ReadString", fmt.Sprintf(`invalid control character found: %d`, c)) return } } return iter.readStringSlowPath() } else if c == 'n' { iter.skipThreeBytes('u', 'l', 'l') return "" } iter.ReportError("ReadString", `expects " or n, but found `+string([]byte{c})) return } func (iter *Iterator) readStringSlowPath() (ret string) { var str []byte var c byte for iter.Error == nil { c = iter.readByte() if c == '"' { return string(str) } if c == '\\' { c = iter.readByte() str = iter.readEscapedChar(c, str) } else { str = append(str, c) } } iter.ReportError("readStringSlowPath", "unexpected end of input") return } func (iter *Iterator) readEscapedChar(c byte, str []byte) []byte { switch c { case 'u': r := iter.readU4() if utf16.IsSurrogate(r) { c = iter.readByte() if iter.Error != nil { return nil } if c != '\\' { iter.unreadByte() str = appendRune(str, r) return str } c = iter.readByte() if iter.Error != nil { return nil } if c != 'u' { str = appendRune(str, r) return iter.readEscapedChar(c, str) } r2 := iter.readU4() if iter.Error != nil { return nil } combined := utf16.DecodeRune(r, r2) if combined == '\uFFFD' { str = appendRune(str, r) str = appendRune(str, r2) } else { str = appendRune(str, combined) } } else { str = appendRune(str, r) } case '"': str = append(str, '"') case '\\': str = append(str, '\\') case '/': str = append(str, '/') case 'b': str = append(str, '\b') case 'f': str = append(str, '\f') case 'n': str = append(str, '\n') case 'r': str = append(str, '\r') case 't': str = append(str, '\t') default: iter.ReportError("readEscapedChar", `invalid escape char after \`) return nil } return str } // ReadStringAsSlice read string from iterator without copying into string form. // The []byte can not be kept, as it will change after next iterator call. func (iter *Iterator) ReadStringAsSlice() (ret []byte) { c := iter.nextToken() if c == '"' { for i := iter.head; i < iter.tail; i++ { // require ascii string and no escape // for: field name, base64, number if iter.buf[i] == '"' { // fast path: reuse the underlying buffer ret = iter.buf[iter.head:i] iter.head = i + 1 return ret } } readLen := iter.tail - iter.head copied := make([]byte, readLen, readLen*2) copy(copied, iter.buf[iter.head:iter.tail]) iter.head = iter.tail for iter.Error == nil { c := iter.readByte() if c == '"' { return copied } copied = append(copied, c) } return copied } iter.ReportError("ReadStringAsSlice", `expects " or n, but found `+string([]byte{c})) return } func (iter *Iterator) readU4() (ret rune) { for i := 0; i < 4; i++ { c := iter.readByte() if iter.Error != nil { return } if c >= '0' && c <= '9' { ret = ret*16 + rune(c-'0') } else if c >= 'a' && c <= 'f' { ret = ret*16 + rune(c-'a'+10) } else if c >= 'A' && c <= 'F' { ret = ret*16 + rune(c-'A'+10) } else { iter.ReportError("readU4", "expects 0~9 or a~f, but found "+string([]byte{c})) return } } return ret } const ( t1 = 0x00 // 0000 0000 tx = 0x80 // 1000 0000 t2 = 0xC0 // 1100 0000 t3 = 0xE0 // 1110 0000 t4 = 0xF0 // 1111 0000 t5 = 0xF8 // 1111 1000 maskx = 0x3F // 0011 1111 mask2 = 0x1F // 0001 1111 mask3 = 0x0F // 0000 1111 mask4 = 0x07 // 0000 0111 rune1Max = 1<<7 - 1 rune2Max = 1<<11 - 1 rune3Max = 1<<16 - 1 surrogateMin = 0xD800 surrogateMax = 0xDFFF maxRune = '\U0010FFFF' // Maximum valid Unicode code point. runeError = '\uFFFD' // the "error" Rune or "Unicode replacement character" ) func appendRune(p []byte, r rune) []byte { // Negative values are erroneous. Making it unsigned addresses the problem. switch i := uint32(r); { case i <= rune1Max: p = append(p, byte(r)) return p case i <= rune2Max: p = append(p, t2|byte(r>>6)) p = append(p, tx|byte(r)&maskx) return p case i > maxRune, surrogateMin <= i && i <= surrogateMax: r = runeError fallthrough case i <= rune3Max: p = append(p, t3|byte(r>>12)) p = append(p, tx|byte(r>>6)&maskx) p = append(p, tx|byte(r)&maskx) return p default: p = append(p, t4|byte(r>>18)) p = append(p, tx|byte(r>>12)&maskx) p = append(p, tx|byte(r>>6)&maskx) p = append(p, tx|byte(r)&maskx) return p } }