Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I unpack various form of integers in a byte buffer in Golang?

Tags:

go

buffer

unpack

I need to extract various fields in a byte buffer. I came up with this solution:

func (fs *FileSystem) readSB() {
    // fs.f is a *os.File
    buf := make([]byte, 1024)
    fs.f.ReadAt(buf, 1024)

    // Offset: type
    var p *bytes.Buffer

    // 0: uint32
    p = bytes.NewBuffer(buf[0:])
    binary.Read(p, binary.LittleEndian, &fs.sb.inodeCount)
    // 4: uint32
    p = bytes.NewBuffer(buf[4:])
    binary.Read(p, binary.LittleEndian, &fs.sb.blockCount)
    // 20: uint32
    p = bytes.NewBuffer(buf[20:])
    binary.Read(p, binary.LittleEndian, &fs.sb.firstDataBlock)
    // 24: uint32
    p = bytes.NewBuffer(buf[24:])
    binary.Read(p, binary.LittleEndian, &fs.sb.blockSize)
    fs.sb.blockSize = 1024 << fs.sb.blockSize
    // 32: uint32
    p = bytes.NewBuffer(buf[32:])
    binary.Read(p, binary.LittleEndian, &fs.sb.blockPerGroup)
    // 40: uint32
    p = bytes.NewBuffer(buf[40:])
    binary.Read(p, binary.LittleEndian, &fs.sb.inodePerBlock)
}

Is there a more better/idiomatic/straightforward way of doing this?

  • I want to keep offsets explicit
  • I want to read from the byte buffer, not seeking and reading from the file when possible.
like image 886
knarf Avatar asked Sep 10 '12 19:09

knarf


People also ask

What is bytes buffer in Golang?

In go language, the buffer belongs to the byte package of the Go language, and we can use these package to manipulate the byte of the string. For example, suppose we have a string. We can read the length of the string with the len function, which will return the numeric length, but what if the strings are too large.

What is [] uint8 in Golang?

type uint8 in Golang is the set of all unsigned 8-bit integers. The set ranges from 0 to 255. You should use type uint8 when you strictly want a positive integer in the range 0-255.

How do you represent bytes in Golang?

Arbitrary character values can be encoded with backslash escapes and used in string or rune literals. Go supports a common format in which a byte is represented as \x followed by two hexadecimal values.

How do I create a byte array in Golang?

To convert String to Byte array in Golang, use the byte() function. A byte is an 8-bit unsigned int. The byte() function takes a string as an input and returns the array.


1 Answers

You could avoid creating a new buffer every time by using .Next() to skip the bytes you don't want to read:

{
    // Offset: type
    p := bytes.NewBuffer(buf)

    // 0: uint32
    binary.Read(p, binary.LittleEndian, &fs.sb.inodeCount)

    // 4: uint32
    binary.Read(p, binary.LittleEndian, &fs.sb.blockCount)

    // Skip [8:20)
    p.Next(12)

    // 20: uint32
    binary.Read(p, binary.LittleEndian, &fs.sb.firstDataBlock)

    // 24: uint32
    binary.Read(p, binary.LittleEndian, &fs.sb.blockSize)
    fs.sb.blockSize = 1024 << fs.sb.blockSize

    // Skip [28:32)
    p.Next(4)

    // 32: uint32
    binary.Read(p, binary.LittleEndian, &fs.sb.blockPerGroup)

    // Skip [36:40)
    p.Next(4)

    // 40: uint32
    binary.Read(p, binary.LittleEndian, &fs.sb.inodePerBlock)
}

Or you could avoid reading chunk by chunk and create a header structure which you read directly using binary.Read:

type Head struct {
    InodeCount      uint32  //  0:4
    BlockCount      uint32  //  4:8
    Unknown1        uint32  //  8:12
    Unknown2        uint32  // 12:16
    Unknown3        uint32  // 16:20
    FirstBlock      uint32  // 20:24
    BlockSize       uint32  // 24:28
    Unknown4        uint32  // 28:32
    BlocksPerGroup  uint32  // 32:36
    Unknown5        uint32  // 36:40
    InodesPerBlock  uint32  // 40:44
}

func main() {
    var header Head

    err = binary.Read(file, binary.LittleEndian, &header)

    if err != nil {
        log.Fatal(err)
    }

    log.Printf("%#v\n", header)
}
like image 98
nemo Avatar answered Jan 02 '23 21:01

nemo