github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/bind/seq/utf16.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package seq 6 7 import ( 8 "fmt" 9 "unicode/utf16" 10 "unsafe" 11 ) 12 13 // Based heavily on package unicode/utf16 from the Go standard library. 14 15 const ( 16 replacementChar = '\uFFFD' // Unicode replacement character 17 maxRune = '\U0010FFFF' // Maximum valid Unicode code point. 18 ) 19 20 const ( 21 // 0xd800-0xdc00 encodes the high 10 bits of a pair. 22 // 0xdc00-0xe000 encodes the low 10 bits of a pair. 23 // the value is those 20 bits plus 0x10000. 24 surr1 = 0xd800 25 surr2 = 0xdc00 26 surr3 = 0xe000 27 28 surrSelf = 0x10000 29 ) 30 31 func writeUint16(b []byte, v rune) { 32 *(*uint16)(unsafe.Pointer(&b[0])) = uint16(v) 33 } 34 35 func (b *Buffer) WriteUTF16(s string) { 36 // first 4 bytes is the length, as int32. written last. 37 // next n bytes is utf-16 string. 38 if len(b.Data)-b.Offset < 4+4*len(s) { 39 b.grow(4 + 4*len(s)) // worst case estimate, everything is surrogate pair 40 } 41 data := b.Data[b.Offset+4:] 42 n := 0 43 for _, v := range s { 44 switch { 45 case v < 0, surr1 <= v && v < surr3, v > maxRune: 46 v = replacementChar 47 fallthrough 48 case v < surrSelf: 49 writeUint16(data[n:], v) 50 n += 2 51 default: 52 // surrogate pair, two uint16 values 53 r1, r2 := utf16.EncodeRune(v) 54 writeUint16(data[n:], r1) 55 writeUint16(data[n+2:], r2) 56 n += 4 57 } 58 } 59 60 // write length at b.Data[b.Offset:], before contents. 61 // length is number of uint16 values, not number of bytes. 62 b.WriteInt32(int32(n / 2)) 63 64 b.Offset += n 65 } 66 67 const maxSliceLen = (1<<31 - 1) / 2 68 69 func (b *Buffer) ReadUTF16() string { 70 size := int(b.ReadInt32()) 71 if size == 0 { 72 return "" 73 } 74 if size < 0 { 75 panic(fmt.Sprintf("string size negative: %d", size)) 76 } 77 u := (*[maxSliceLen]uint16)(unsafe.Pointer(&b.Data[b.Offset]))[:size] 78 s := string(utf16.Decode(u)) // TODO: save the []rune alloc 79 b.Offset += 2 * size 80 81 return s 82 }