I am trying to create a go program that can read and create RPM files without the need of librpm and rpmbuild. Most of the reason for this is to get a better understanding of programming in go.
I am parsing an RPM based off the following: https://github.com/jordansissel/fpm/wiki/rpm-internals
I am looking at the header and trying to parse the number of tags + the length, and I have the following code
fi, err := os.Open("golang-1.1-2.fc19.i686.rpm")
...
// header
head := make([]byte, 16)
// read a chunk
_, err = fi.Read(head)
if err != nil && err != io.EOF { panic(err) }
fmt.Printf("Magic number %s
", head[:8])
tags, read := binary.Varint(head[8:12])
fmt.Printf("Tag Count: %d
", tags)
fmt.Printf("Read %d
", read)
length, read := binary.Varint(head[12:16])
fmt.Printf("Length : %d
", length)
fmt.Printf("Read %d
", read)
I get back the following:
Magic number ���
Tag Count: 0
Read 1
Length : 0
Read 1
I printed out the slice and I see this:
Tag bytes: [0 0 0 7]
Length bytes: [0 0 4 132]
I then tried just doing this:
length, read = binary.Varint([]byte{4, 132})
which returns length as 2 and read 1.
Based off what I am reading, the tag and length should be "4 byte 'tag count'", so how would I get the four bytes as one number?
EDIT: Based off the feedback from @nick-craig-wood and @james-henstridge below is my following prototype code that does what Im looking for:
package main
import (
"io"
"os"
"fmt"
"encoding/binary"
"bytes"
)
type Header struct {
// begin with the 8-byte header magic value: 8D AD E8 01 00 00 00 00
Magic uint64
// 4 byte 'tag count'
Count uint32
// 4 byte 'data length'
Length uint32
}
func main() {
// open input file
fi, err := os.Open("golang-1.1-2.fc19.i686.rpm")
if err != nil { panic(err) }
// close fi on exit and check for its returned error
defer func() {
if err := fi.Close(); err != nil {
panic(err)
}
}()
// ignore lead
fi.Seek(96, 0)
// header
head := make([]byte, 16)
// read a chunk
_, err = fi.Read(head)
if err != nil && err != io.EOF { panic(err) }
fmt.Printf("Magic number %s
", head[:8])
tags := binary.BigEndian.Uint32(head[8:12])
fmt.Printf("Count Count: %d
", tags)
length := binary.BigEndian.Uint32(head[12:16])
fmt.Printf("Length : %d
", length)
// read it as a struct
buf := bytes.NewBuffer(head)
header := Header{}
err = binary.Read(buf, binary.BigEndian, &header)
if err != nil {
fmt.Println("binary.Read failed:", err)
}
fmt.Printf("header = %#v
", header)
fmt.Printf("Count bytes: %d
", header.Count)
fmt.Printf("Length bytes: %d
", header.Length)
}