Переход байта в целочисленное кодирование с помощью RPM

Я пытаюсь создать программу go, которая может читать и создавать файлы RPM без необходимости 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 байт" счетчика тегов ", так как я могу получить четыре байта как один номер?

EDIT: Основываясь на обратной связи от @nick-craig-wood и @james-henstridge ниже, это мой следующий код прототипа, который делает то, что Im ищет:

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 ******
 // 4 byte 'tag count'
 Count ******
 // 4 byte 'data length'
 Length ******
}

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

 length := binary.BigEndian.******(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)
}
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 ******
 // 4 byte 'tag count'
 Count ******
 // 4 byte 'data length'
 Length ******
}

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}

Игровая площадка


Данные, которые вы читаете, не выглядят так, как будто это целочисленная кодировка переменной длины переменной переменной.

Вместо этого вы, вероятно, хотите binary.BigEndian.******():

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

licensed under cc by-sa 3.0 with attribution.