github.com/camlistore/go4@v0.0.0-20200104003542-c7e774b10ea0/strutil/strconv.go (about) 1 /* 2 Copyright 2013 The Perkeep Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package strutil 18 19 import ( 20 "errors" 21 "strconv" 22 ) 23 24 // ParseUintBytes is like strconv.ParseUint, but using a []byte. 25 func ParseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) { 26 var cutoff, maxVal uint64 27 28 if bitSize == 0 { 29 bitSize = int(strconv.IntSize) 30 } 31 32 s0 := s 33 switch { 34 case len(s) < 1: 35 err = strconv.ErrSyntax 36 goto Error 37 38 case 2 <= base && base <= 36: 39 // valid base; nothing to do 40 41 case base == 0: 42 // Look for octal, hex prefix. 43 switch { 44 case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'): 45 base = 16 46 s = s[2:] 47 if len(s) < 1 { 48 err = strconv.ErrSyntax 49 goto Error 50 } 51 case s[0] == '0': 52 base = 8 53 default: 54 base = 10 55 } 56 57 default: 58 err = errors.New("invalid base " + strconv.Itoa(base)) 59 goto Error 60 } 61 62 n = 0 63 cutoff = cutoff64(base) 64 maxVal = 1<<uint(bitSize) - 1 65 66 for i := 0; i < len(s); i++ { 67 var v byte 68 d := s[i] 69 switch { 70 case '0' <= d && d <= '9': 71 v = d - '0' 72 case 'a' <= d && d <= 'z': 73 v = d - 'a' + 10 74 case 'A' <= d && d <= 'Z': 75 v = d - 'A' + 10 76 default: 77 n = 0 78 err = strconv.ErrSyntax 79 goto Error 80 } 81 if int(v) >= base { 82 n = 0 83 err = strconv.ErrSyntax 84 goto Error 85 } 86 87 if n >= cutoff { 88 // n*base overflows 89 n = 1<<64 - 1 90 err = strconv.ErrRange 91 goto Error 92 } 93 n *= uint64(base) 94 95 n1 := n + uint64(v) 96 if n1 < n || n1 > maxVal { 97 // n+v overflows 98 n = 1<<64 - 1 99 err = strconv.ErrRange 100 goto Error 101 } 102 n = n1 103 } 104 105 return n, nil 106 107 Error: 108 return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err} 109 } 110 111 // Return the first number n such that n*base >= 1<<64. 112 func cutoff64(base int) uint64 { 113 if base < 2 { 114 return 0 115 } 116 return (1<<64-1)/uint64(base) + 1 117 }