go - Variable length two's complement to int64 -
i'm attempting write go program parse ans.1 ber two's complement integer encoding. however, integer can have either 1, 2, 3 or 4 byte length encoding (depending on size).
according specification (http://www.itu.int/itu-t/studygroups/com17/languages/x.690-0207.pdf) leftmost bit complement.
what's clean way this?
func parseint(b []byte) (int64, error) { switch len(b) { case 1: // works return int64(b[0]&0x7f) - int64(b[0]&0x80), nil case 2: // left byte of b[0] -32768 case 3: // left byte of b[0] -8388608 case 4: // left byte of b[0] -2147483648 (and on 5, 6, 7, 8) case 5: case 6: case 7: case 8: default: return 0, errors.new("value not fit in int64") } } parseint([]byte{0xfe}) // should return (-2, nil) parseint([]byte{0xfe, 0xff}) // should return (-257, nil) parseint([]byte{0x01, 0x00}) // should return (256, nil)
easier understand if read bytes end:
- you don't have shift last byte
- left-shift last byte 8 (8 bits in byte)
- left-shift 2nd last byte 16
- ...
- and first byte use 7 bits, leftmost bit special.
the leftmost bit of first byte b[0]&080
tells if have add offset result. offset optionally added -1
multiplied number input mean having 1 bit set , others being 0
, -1 * (1 << (len(b)*8 - 1)) = 0x80 << (len(b)*8 - 8)
.
examples. if input is...
- 1 byte:
int64(b[0]&0x7f) - int64(b[0]&0x80)
- 2 bytes:
int64(b[0]&0x7f)<<8 + int64(b[1]) - int64(b[0]&0x80)<<8
- 3 bytes:
int64(b[0]&0x7f)<<16 + int64(b[1])<<8 + int64(b[2]) - int64(b[0]&0x80)<<16
all these cases can covered nice loop.
here's compact implementation (try on go playground):
func parseint(b []byte) (int64, error) { if len(b) > 8 { return 0, errors.new("value not fit in int64") } var n int64 i, v := range b { shift := uint((len(b) - - 1) * 8) if == 0 && v&0x80 != 0 { n -= 0x80 << shift v &= 0x7f } n += int64(v) << shift } return n, nil }
Comments
Post a Comment