使用RPMs进行字节到整数编码

huangapple go评论143阅读模式
英文:

Go byte to integer encoding with RPMs

问题

我正在尝试创建一个能够读取和创建RPM文件的Go程序,而无需使用librpm和rpmbuild。这样做的主要原因是为了更好地理解Go编程。

我正在解析一个基于以下链接的RPM文件:https://github.com/jordansissel/fpm/wiki/rpm-internals

我正在查看头部并尝试解析标签的数量+长度,我有以下代码:

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\n", head[:8])
tags, read := binary.Varint(head[8:12])
fmt.Printf("Tag Count: %d\n", tags)
fmt.Printf("Read %d\n", read)

length, read := binary.Varint(head[12:16])
fmt.Printf("Length : %d\n", length)
fmt.Printf("Read %d\n", read)

我得到以下结果:

Magic number ���
Tag Count: 0
Read 1
Length : 0
Read 1

我打印出了切片,看到了这个:

Tag bytes: [0 0 0 7]
Length bytes: [0 0 4 132]

然后我尝试只做这个:

length, read = binary.Varint([]byte{4, 132})

这将返回长度为2,读取为1。

根据我所读的,标签和长度应该是"4字节的标签计数",那么我如何将这四个字节作为一个数字获取呢?

编辑:
根据@nick-craig-wood和@james-henstridge的反馈,以下是我所需的原型代码:

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\n", head[:8])
    tags := binary.BigEndian.Uint32(head[8:12])
    fmt.Printf("Count Count: %d\n", tags)

    length := binary.BigEndian.Uint32(head[12:16])
    fmt.Printf("Length : %d\n", 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\n", header)
    fmt.Printf("Count bytes: %d\n", header.Count)
    fmt.Printf("Length bytes: %d\n", header.Length)
}
英文:

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\n", head[:8])
tags, read := binary.Varint(head[8:12])
fmt.Printf("Tag Count: %d\n", tags)
fmt.Printf("Read %d\n", read)
length, read := binary.Varint(head[12:16])
fmt.Printf("Length : %d\n", length)
fmt.Printf("Read %d\n", 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\n", head[:8])
tags := binary.BigEndian.Uint32(head[8:12])
fmt.Printf("Count Count: %d\n", tags)
length := binary.BigEndian.Uint32(head[12:16])
fmt.Printf("Length : %d\n", 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\n", header)
fmt.Printf("Count bytes: %d\n", header.Count)
fmt.Printf("Length bytes: %d\n", header.Length)
}

答案1

得分: 2

你正在阅读的数据似乎不是Go语言的可变长度整数编码。

相反,你可能想要使用binary.BigEndian.Uint32()函数:

tags := binary.BigEndian.Uint32(head[8:12])
length := binary.BigEndian.Uint32(head[12:16])
英文:

The data you are reading doesn't look like it is in Go's variable length integer encoding.

Instead, you probably want binary.BigEndian.Uint32():

tags := binary.BigEndian.Uint32(head[8:12])
length := binary.BigEndian.Uint32(head[12:16])

答案2

得分: 2

首先,不要使用Varint - 它不会做你认为它会做的事情!

将其解码为Go结构体是最方便的方法,代码如下:

package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
)

type Header struct {
	// 以8字节的头部魔术值开始:8D AD E8 01 00 00 00 00
	Magic  uint64
	// 4字节的'tag count'
	Count  uint32
	// 4字节的'data length'
	Length uint32
}

var data = []byte{0x8D, 0xAD, 0xE8, 0x01, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 4, 132}

func main() {
	buf := bytes.NewBuffer(data)
	header := Header{}
	err := binary.Read(buf, binary.BigEndian, &header)
	if err != nil {
		fmt.Println("binary.Read failed:", err)
	}
	fmt.Printf("header = %#v\n", header)
}

输出结果为:

header = main.Header{Magic:0x8dade80100000000, Count:0x7, Length:0x484}

Playground链接

英文:

Firstly don't use Varint - it doesn't do what you think it does!

Decode like this into a go structure is the most convenient way

package main
import (
"bytes"
"encoding/binary"
"fmt"
)
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
}
var data = []byte{0x8D, 0xAD, 0xE8, 0x01, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 4, 132}
func main() {
buf := bytes.NewBuffer(data)
header := Header{}
err := binary.Read(buf, binary.BigEndian, &header)
if err != nil {
fmt.Println("binary.Read failed:", err)
}
fmt.Printf("header = %#v\n", header)
}

Prints

header = main.Header{Magic:0x8dade80100000000, Count:0x7, Length:0x484}

Playground link

huangapple
  • 本文由 发表于 2013年9月27日 13:35:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/19043366.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定