Cannot convert byte to int in Golang - go

This is strange but I cannot convert byte value into int.
Here is the code:
fmt.Println("numMsgsByte is:", numMsgsByte)
numMsgsStr := string(numMsgsByte)
fmt.Println("numMsgsStr is:", numMsgsStr)
numMsgs, err = strconv.Atoi(numMsgsStr)
if err != nil {
log.Println("error in msg conversion", err)
return 0
}
The terminal print out:
numMsgsByte is: [5]
numMsgsStr is:
counter.go:51: error in msg conversion strconv.Atoi: parsing "\x05": invalid syntax
What could be wrong here? How can I fix it?

numMsgByte is not a byte, it is a []byte, which contains 5 (not "5"). When you convert it to string using string(numMsgByte), you get a string "\x5".
What you need is: int(numMsgType[0])

The correct way to get an integer out of Redis using redigo would be to just use redis.Int in the first place, instead of using redis.Bytes and trying to convert the result to an int yourself.
In general though, to convert an arbitrary byte array to the integer it represents, you would use the encoding/binary package. You'll need to know some key details about the byte array though:
Does it represent a signed or unsigned value?
Of what width? 32 bit? 64 bit?
Of what byte order? Big-endian? Little-endian?
Are you sure it's represented as an integer, not e.g. a float, or a string representation of a number?
To quote the example from the docs:
b := []byte{0xe8, 0x03, 0xd0, 0x07}
x1 := binary.LittleEndian.Uint16(b[0:])
x2 := binary.LittleEndian.Uint16(b[2:])
fmt.Printf("%#04x %#04x\n", x1, x2)

Related

Converting Hex to signed Int in Go

I want to convert a hex string to a signed integer Value in Go. My input value is "FF60" and I want the output to be "-160". When I use the following function, the result is "65376", which represents the unsigned representation.
value, err := strconv.ParseInt("FF60", 16, 64)
I would have expected the outcome of 65376 when using the ParseUInt function.
Any help would be really appreciated.
The third parameter of strconv.ParseInt() tells the bitsize of the integer you want to parse. 0xff60 parsed as a 64-bit integer is indeed 65376.
You actually want to parse it as a 16-bit integer, so pass 16 as the bitsize. Doing so you will get an error though:
strconv.ParseInt: parsing "FF60": value out of range
Which is true: 0xFF60 (which is 65376) is outside of the valid range of int16 (valid int16 range is [-32768..32767]).
So what you may do is parse it as an unsigned 16-bit integer using strconv.ParseUint(), then convert the result to a signed 16-bit integer:
value, err := strconv.ParseUint("FF60", 16, 16)
fmt.Println(value, err)
fmt.Println(int16(value))
This will output (try it on the Go Playground):
65376 <nil>
-160

Scramble/unscramble an integer value to/from hexadecimal string

I'm attempting to implement some Go code to solve a problem in which I need to sufficiently obfuscate a known integer value by converting it into a seemingly random hexadecimal string, when provided a known key value as an additional input parameter. The resulting hexadecimal string needs to always be the same number of characters in length (ideally, <= 32 characters).
Furthermore, using the same key string value, I need to un-obfuscate the hexadecimal string back into the original integer. For additional context, I'd like to satisfy the following function signatures (but am open to alternative methods, if necessary):
func Scramble(key string, value int32) string {
// TODO: Given a known key and value, generate a sufficiently unpredictable hexadecimal string.
}
func Unscramble(key string, value string) int32 {
// TODO: Given a known key and value, generate the integer that created the hexadecimal string.
}
func main() {
key := "Something super secret!"
scrambled := Scramble(key, 135)
fmt.Printf("Scrambled: %s\n", scrambled) // Scrambled: a1dec128b590b9ec3281110d6d188c26
unscrambled := Unscramble(key, scrambled)
fmt.Printf("Unscrambled: %d\n", unscrambled) // Unscrambled: 135
}
I think XOR'ing may be the right direction, but I'm unsure and not particularly familiar with the topic yet.
Any insight/direction would be greatly appreciated! Please let me know if I can provide any additional context/clarifications.
There are many native or external packages to achieve what you want, but if you want to implement this yourself for a learning experience, you can try the following tack:
Rather than shuffle your data back and forth between string and int32 format - keep the data in its raw type and use Stringer methods to convert to hex - and helper methods/functions to convert to the desired type. This simplifies the scrambling/unscrambling logic - as the input types are the same for both.
// Code custom type so we can add stringer methods
type Code uint32
// String converts code to hex string format
func (c Code) String() string {
return fmt.Sprintf("%x", uint32(c))
}
// CodeFromString gets a code from a hex string
func CodeFromString(hexs string) (Code, error) {
ui, err := strconv.ParseUint(hexs, 16, 32)
if err != nil {
return 0, err
}
return Code(ui), nil
}
// XOR scrambles/unscrambles
func XOR(key, value Code) Code {
return key ^ value
}
And to use:
keyHex := "74490a85"
valueHex := "d195c729"
value, _ := CodeFromString(valueHex)
key, _ := CodeFromString(keyHex)
scrambled := XOR(key, value)
unscrambled := XOR(key, scrambled)
Playground Example: https://play.golang.org/p/y5pbac_f8Z1

Display base 10 representation of huge hexa string?

Trying to find how to have this hexa string "58068906d6194c6cbda7a6df" into it's base 10 representation.
I tried with this:
i, err := strconv.Parse("58068906d6194c6cbda7a6df", 16, 64)
Obviously I'm getting this error: parsing "58068906d6194c6cbda7a6df"; value out of range
I also need to take the base 10 string representation and get this hexa value back after some processing. i.e.:
base10 := "58068906d6194c6cbda7a6df" => to base 10 string
some processing
hexa := base10 => to base 16 string
Can I use the fmt package to dislpay the base 10? I know that displaying the hexa of a base 10 I could use %x, but what can I do with an existing string?
Thanks for your help, for a reason I cannot understand, I'm unable to find any way to do this.
Your hex value is larger than int64 can hold, so you have to use a big.Int
https://play.golang.org/p/OPPL43u6nB
i := new(big.Int)
i.SetString("58068906d6194c6cbda7a6df", 16)
fmt.Println(i)
To get a hex string representation from a big.Int, you can use the Text method:
hex := i.Text(16)

Putting int8 into byte array

I have the following byte array:
buf := make([]byte, 1)
var value int8
value = 45
buf[0] = value // cannot use type int8 as type []byte in assignment
And when I want to put a char value into the byte array I get the error that I cannot use type int8 as type []byte in assignment. What's wrong? How do I do this?
The issue you're having their is that although int8 and byte are roughly equivalent, they're not the same type. Go is a little stricter about this than, say, PHP (which isn't strict about much). You can get around this by explicitly casting the value to byte:
buf := make([]byte, 1)
var value int8
value = 45
buf[0] = byte(value) // cast int8 to byte
Try this:
buf := make([]byte, 1)
var value int8
value = 45
buf[0] = byte(value)
UPDATE: Took out the code converting negative numbers to positive ones. It appears that byte(...) already does this conversion in current versions of Go.

Go []byte to Little/Big-Endian Signed Integer or Float?

I am able to convert []byte into unsigned integers:
a := binary.LittleEndian.Uint16(sampleA)
b := binary.BigEndian.Uint32(sampleB)
This leverages the BigEndian and LittleEndian types within the Go package https://golang.org/src/encoding/binary/binary.go.
This provides Uint16() however there are no equivalent Int16() or Float32().
Any thoughts on why not? Also, how ought this be done?
Converting numeric types into a series of bytes ([]byte) and vice versa is about the endianness. How you interpret the result is entirely up to you.
All you need is to assemble a 16-bit, 32-bit or 64-bit value, once it's done, you can interpret the result as you want.
For example if you already have a uint16 value, to use it as a signed value, all you need is a type conversion because the memory layout of an uint16 and int16 is the same (converting from uint16 to int16 doesn't change the memory representation just the type):
a := binary.LittleEndian.Uint16(sampleA)
// If you need int16:
a2 := int16(a)
Similarly:
a := binary.LittleEndian.Uint64(sampleA)
// If you need int64:
a2 := int64(a)
The situation is a little more complicated with uint -> float conversion as using a simple type conversion would try to convert the numeric value and not just change the type (and thus would change the memory representation).
For converting unsigned integers to float types, you can use functions of the math package, namely math.Float32frombits() and math.Float64frombits(), and for the reverse direction (converting a float value to an unsigned integer) having the same memory layout: math.Float32bits() and math.Float64bits().
For example:
a := binary.LittleEndian.Uint64(sampleA)
// If you need a float64:
a2 := math.Float64frombits(a)
If you would look into the implementation of these functions from the math package, you can see that the memory value/layout is not manipulated, it is just "viewed" as a different type, by using the unsafe package. For example:
func Float32frombits(b uint32) float32 { return *(*float32)(unsafe.Pointer(&b)) }
As mentioned by Paul, the binary package provides Read() and Write() functions to do these conversions under the hood so you don't need to.
Showcasing using the same "pi" example (from the doc of binary.Read()):
b := []byte{0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40}
// USING binary.Read()
var pi float64
buf := bytes.NewReader(b)
err := binary.Read(buf, binary.LittleEndian, &pi)
if err != nil {
fmt.Println("binary.Read failed:", err)
}
fmt.Println(pi)
// Using LittleEndian.Uint64() and math.Float64frombits()
a := binary.LittleEndian.Uint64(b)
a2 := math.Float64frombits(a)
fmt.Println(a2)
Output (try it on the Go Playground):
3.141592653589793
3.141592653589793
The ByteOrder type provides a low-level API for decoding binary values. To read float64 or other types, you can use binary.Read. There's an example on the godoc page for the binary package, which I've copied here:
var pi float64
b := []byte{0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40}
buf := bytes.NewReader(b)
err := binary.Read(buf, binary.LittleEndian, &pi)
if err != nil {
fmt.Println("binary.Read failed:", err)
}
fmt.Print(pi)
There's no functions for decoding float16, because that's not a type in Go.

Resources