0

我正在尝试创建一个无需 librpm 和 rpmbuild 即可读取和创建 RPM 文件的 go 程序。这样做的大部分原因是为了更好地理解 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)
}
4

2 回答 2

2

您正在读取的数据看起来不像 Go 的可变长度整数编码。

相反,您可能想要binary.BigEndian.Uint32()

tags := binary.BigEndian.Uint32(head[8:12])
length := binary.BigEndian.Uint32(head[12:16])
于 2013-09-27T05:46:12.830 回答
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}

游乐场链接

于 2013-09-27T05:55:53.223 回答