我正在尝试创建一个可以读取和创建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)
}
答案 0 :(得分:2)
您正在阅读的数据与Go的可变长度整数编码看起来不一样。
相反,您可能需要binary.BigEndian.Uint32()
:
tags := binary.BigEndian.Uint32(head[8:12])
length := binary.BigEndian.Uint32(head[12:16])
答案 1 :(得分:2)
首先不要使用Varint - 它不会像你想象的那样做!
像这样解码为go结构是最方便的方式
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)
}
打印
header = main.Header{Magic:0x8dade80100000000, Count:0x7, Length:0x484}