github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/bind/seq/string.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 "errors" 9 "fmt" 10 "unicode/utf16" 11 "unsafe" 12 ) 13 14 // Based heavily on package unicode/utf16 from the Go standard library. 15 16 const ( 17 replacementChar = '\uFFFD' // Unicode replacement character 18 maxRune = '\U0010FFFF' // Maximum valid Unicode code point. 19 ) 20 21 const ( 22 // 0xd800-0xdc00 encodes the high 10 bits of a pair. 23 // 0xdc00-0xe000 encodes the low 10 bits of a pair. 24 // the value is those 20 bits plus 0x10000. 25 surr1 = 0xd800 26 surr2 = 0xdc00 27 surr3 = 0xe000 28 29 surrSelf = 0x10000 30 ) 31 32 func writeUint16(b []byte, v rune) { 33 *(*uint16)(unsafe.Pointer(&b[0])) = uint16(v) 34 } 35 36 func (b *Buffer) WriteUTF16(s string) { 37 // The first 4 bytes is the length, as int32 (4-byte aligned). 38 // written last. 39 // The next n bytes is utf-16 string (1-byte aligned). 40 offset0 := align(b.Offset, 4) // length. 41 offset1 := align(offset0+4, 1) // contents. 42 43 if len(b.Data)-offset1 < 4*len(s) { 44 // worst case estimate, everything is surrogate pair 45 b.grow(offset1 + 4*len(s) - len(b.Data)) 46 } 47 data := b.Data[offset1:] 48 n := 0 49 for _, v := range s { 50 switch { 51 case v < 0, surr1 <= v && v < surr3, v > maxRune: 52 v = replacementChar 53 fallthrough 54 case v < surrSelf: 55 writeUint16(data[n:], v) 56 n += 2 57 default: 58 // surrogate pair, two uint16 values 59 r1, r2 := utf16.EncodeRune(v) 60 writeUint16(data[n:], r1) 61 writeUint16(data[n+2:], r2) 62 n += 4 63 } 64 } 65 66 // write length at b.Data[b.Offset:], before contents. 67 // length is number of uint16 values, not number of bytes. 68 b.WriteInt32(int32(n / 2)) 69 70 b.Offset = offset1 + n 71 } 72 73 func (b *Buffer) WriteUTF8(s string) { 74 n := len(s) 75 b.WriteInt32(int32(n)) 76 if len(s) == 0 { 77 return 78 } 79 offset := align(b.Offset, 1) 80 if len(b.Data)-offset < n { 81 b.grow(offset + n - len(b.Data)) 82 } 83 copy(b.Data[offset:], s) 84 b.Offset = offset + n 85 } 86 87 const maxSliceLen = (1<<31 - 1) / 2 88 89 func (b *Buffer) ReadError() error { 90 if s := b.ReadString(); s != "" { 91 return errors.New(s) 92 } 93 return nil 94 } 95 96 func (b *Buffer) ReadUTF16() string { 97 size := int(b.ReadInt32()) 98 if size == 0 { 99 return "" 100 } 101 if size < 0 { 102 panic(fmt.Sprintf("string size negative: %d", size)) 103 } 104 offset := align(b.Offset, 1) 105 u := (*[maxSliceLen]uint16)(unsafe.Pointer(&b.Data[offset]))[:size] 106 s := string(utf16.Decode(u)) // TODO: save the []rune alloc 107 b.Offset = offset + 2*size 108 109 return s 110 } 111 112 func (b *Buffer) ReadUTF8() string { 113 size := int(b.ReadInt32()) 114 if size == 0 { 115 return "" 116 } 117 if size < 0 { 118 panic(fmt.Sprintf("string size negative: %d", size)) 119 } 120 offset := align(b.Offset, 1) 121 b.Offset = offset + size 122 return string(b.Data[offset : offset+size]) 123 }