go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/data/cmpbin/string.go (about) 1 // Copyright 2015 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cmpbin 16 17 import ( 18 "bytes" 19 "errors" 20 "io" 21 "math" 22 ) 23 24 // ReadByteLimit is the limit of how many bytes ReadBytes and ReadString are 25 // willing to deserialize before returning ErrByteLimitExceeded. It is currently 26 // set to allow 2MB of user data (taking encoding size overhead into account). 27 var ReadByteLimit = int(math.Ceil(2 * 1024 * 1024 * 8 / 7)) 28 29 // ErrByteLimitExceeded is returned from ReadBytes and ReadString when they 30 // attempt to read more than ReadByteLimit bytes. 31 var ErrByteLimitExceeded = errors.New("cmbpin: too big! tried to read > cmpbin.ReadByteLimit") 32 33 // WriteString writes an encoded string to buf, returning the number of bytes 34 // written, and any write error encountered. 35 func WriteString(buf io.ByteWriter, s string) (n int, err error) { 36 return WriteBytes(buf, []byte(s)) 37 } 38 39 // ReadString reads an encoded string from buf, returning the number of bytes 40 // read, and any read error encountered. 41 func ReadString(buf io.ByteReader) (ret string, n int, err error) { 42 b, n, err := ReadBytes(buf) 43 if err != nil { 44 return 45 } 46 ret = string(b) 47 return 48 } 49 50 // WriteBytes writes an encoded []byte to buf, returning the number of bytes 51 // written, and any write error encountered. 52 func WriteBytes(buf io.ByteWriter, data []byte) (n int, err error) { 53 wb := func(b byte) (err error) { 54 if err = buf.WriteByte(b); err == nil { 55 n++ 56 } 57 return 58 } 59 60 acc := byte(0) 61 for i := 0; i < len(data); i++ { 62 m := uint(i % 7) 63 b := data[i] 64 if err = wb(acc | 1 | ((b & (0xff << (m + 1))) >> m)); err != nil { 65 return 66 } 67 acc = (b << (7 - m)) 68 if m == 6 { 69 if err = wb(acc | 1); err != nil { 70 return 71 } 72 acc = 0 73 } 74 } 75 err = wb(acc) 76 return 77 } 78 79 // ReadBytes reads an encoded []byte from buf, returning the number of bytes 80 // read, and any read error encountered. 81 func ReadBytes(buf io.ByteReader) (ret []byte, n int, err error) { 82 tmpBuf := bytes.Buffer{} 83 acc := byte(0) 84 for i := 0; i < ReadByteLimit; i++ { 85 o := byte(0) 86 if o, err = buf.ReadByte(); err != nil { 87 return 88 } 89 n++ 90 91 b := o & 0xfe // user data 92 m := uint(i % 8) 93 94 if m == 0 { 95 acc = b 96 } else { 97 // ignore err since bytes.Buffer.WriteByte can never return one. 98 _ = tmpBuf.WriteByte(acc | (b >> (8 - m))) 99 acc = (b << m) 100 } 101 102 if o&1 == 0 { // stop bit is 0 103 ret = tmpBuf.Bytes() 104 return 105 } 106 } 107 err = ErrByteLimitExceeded 108 return 109 }