2020-06-08 03:29:51 +03:00
|
|
|
package protobuf
|
|
|
|
|
2022-02-01 18:07:41 +03:00
|
|
|
// https://developers.google.com/protocol-buffers/docs/encoding
|
|
|
|
|
2020-06-08 03:29:51 +03:00
|
|
|
import (
|
2021-12-09 19:15:21 +03:00
|
|
|
"embed"
|
|
|
|
|
2021-08-17 13:06:32 +03:00
|
|
|
"github.com/wader/fq/format"
|
2024-04-01 19:39:45 +03:00
|
|
|
"github.com/wader/fq/internal/mathx"
|
2021-08-17 13:06:32 +03:00
|
|
|
"github.com/wader/fq/pkg/decode"
|
2022-07-16 19:39:57 +03:00
|
|
|
"github.com/wader/fq/pkg/interp"
|
2021-12-02 00:48:25 +03:00
|
|
|
"github.com/wader/fq/pkg/scalar"
|
2020-06-08 03:29:51 +03:00
|
|
|
)
|
|
|
|
|
2022-09-10 19:28:54 +03:00
|
|
|
//go:embed protobuf.md
|
2021-12-09 19:15:21 +03:00
|
|
|
var protobufFS embed.FS
|
|
|
|
|
2020-06-08 03:29:51 +03:00
|
|
|
func init() {
|
2023-03-29 01:36:55 +03:00
|
|
|
interp.RegisterFormat(
|
|
|
|
format.Protobuf,
|
|
|
|
&decode.Format{
|
|
|
|
Description: "Protobuf",
|
|
|
|
DecodeFn: protobufDecode,
|
|
|
|
})
|
2022-07-27 14:20:48 +03:00
|
|
|
interp.RegisterFS(protobufFS)
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
wireTypeVarint = 0
|
|
|
|
wireType64Bit = 1
|
|
|
|
wireTypeLengthDelimited = 2
|
|
|
|
wireType32Bit = 5
|
|
|
|
)
|
|
|
|
|
2022-09-30 14:58:23 +03:00
|
|
|
var wireTypeNames = scalar.UintMapSymStr{
|
2022-04-05 14:57:55 +03:00
|
|
|
0: "varint",
|
|
|
|
1: "64bit",
|
|
|
|
2: "length_delimited",
|
|
|
|
5: "32bit",
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func protobufDecodeField(d *decode.D, pbm *format.ProtoBufMessage) {
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldStruct("field", func(d *decode.D) {
|
2022-08-20 13:05:07 +03:00
|
|
|
keyN := d.FieldULEB128("key_n")
|
2020-06-08 03:29:51 +03:00
|
|
|
fieldNumber := keyN >> 3
|
|
|
|
wireType := keyN & 0x7
|
2022-09-30 14:58:23 +03:00
|
|
|
d.FieldValueUint("field_number", fieldNumber)
|
|
|
|
d.FieldValueUint("wire_type", wireType, scalar.UintSym(wireTypeNames[wireType]))
|
2020-06-08 03:29:51 +03:00
|
|
|
|
|
|
|
var value uint64
|
|
|
|
var length uint64
|
2023-10-29 18:05:52 +03:00
|
|
|
var valuePos int64
|
2020-06-08 03:29:51 +03:00
|
|
|
switch wireType {
|
|
|
|
case wireTypeVarint:
|
2022-08-20 13:05:07 +03:00
|
|
|
value = d.FieldULEB128("wire_value")
|
2020-06-08 03:29:51 +03:00
|
|
|
case wireType64Bit:
|
|
|
|
value = d.FieldU64("wire_value")
|
|
|
|
case wireTypeLengthDelimited:
|
2022-08-20 13:05:07 +03:00
|
|
|
length = d.FieldULEB128("length")
|
2023-10-29 18:05:52 +03:00
|
|
|
valuePos = d.Pos()
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldRawLen("wire_value", int64(length)*8)
|
2020-06-08 03:29:51 +03:00
|
|
|
case wireType32Bit:
|
|
|
|
value = d.FieldU32("wire_value")
|
|
|
|
}
|
|
|
|
|
|
|
|
if pbm != nil {
|
|
|
|
if pbf, ok := (*pbm)[int(fieldNumber)]; ok {
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldValueStr("name", pbf.Name)
|
|
|
|
d.FieldValueStr("type", format.ProtoBufTypeNames[uint64(pbf.Type)])
|
2020-06-08 03:29:51 +03:00
|
|
|
|
|
|
|
switch pbf.Type {
|
|
|
|
case format.ProtoBufTypeInt32, format.ProtoBufTypeInt64:
|
2024-04-01 19:39:45 +03:00
|
|
|
v := mathx.ZigZag[uint64, int64](value)
|
2022-09-30 14:58:23 +03:00
|
|
|
d.FieldValueSint("value", v)
|
2020-06-08 03:29:51 +03:00
|
|
|
if len(pbf.Enums) > 0 {
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldValueStr("enum", pbf.Enums[uint64(v)])
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
|
|
|
case format.ProtoBufTypeUInt32, format.ProtoBufTypeUInt64:
|
2022-09-30 14:58:23 +03:00
|
|
|
d.FieldValueUint("value", value)
|
2020-06-08 03:29:51 +03:00
|
|
|
if len(pbf.Enums) > 0 {
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldValueStr("enum", pbf.Enums[value])
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
|
|
|
case format.ProtoBufTypeSInt32, format.ProtoBufTypeSInt64:
|
|
|
|
// TODO: correct? 32 different?
|
2024-04-01 19:39:45 +03:00
|
|
|
v := mathx.TwosComplement(64, value)
|
2022-09-30 14:58:23 +03:00
|
|
|
d.FieldValueSint("value", v)
|
2020-06-08 03:29:51 +03:00
|
|
|
if len(pbf.Enums) > 0 {
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldValueStr("enum", pbf.Enums[uint64(v)])
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
|
|
|
case format.ProtoBufTypeBool:
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldValueBool("value", value != 0)
|
2020-06-08 03:29:51 +03:00
|
|
|
case format.ProtoBufTypeEnum:
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldValueStr("enum", pbf.Enums[value])
|
2020-06-08 03:29:51 +03:00
|
|
|
case format.ProtoBufTypeFixed64:
|
|
|
|
// TODO:
|
|
|
|
case format.ProtoBufTypeSFixed64:
|
|
|
|
// TODO:
|
|
|
|
case format.ProtoBufTypeDouble:
|
|
|
|
// TODO:
|
|
|
|
case format.ProtoBufTypeString:
|
2023-10-29 18:05:52 +03:00
|
|
|
d.SeekAbs(valuePos)
|
|
|
|
d.FieldUTF8("value", int(length))
|
2020-06-08 03:29:51 +03:00
|
|
|
case format.ProtoBufTypeBytes:
|
2023-10-29 18:05:52 +03:00
|
|
|
d.SeekAbs(valuePos)
|
|
|
|
d.FieldRawLen("value", int64(length)*8)
|
2020-06-08 03:29:51 +03:00
|
|
|
case format.ProtoBufTypeMessage:
|
|
|
|
// TODO: test
|
2022-01-13 20:34:59 +03:00
|
|
|
d.FramedFn(int64(length)*8, func(d *decode.D) {
|
2020-06-08 03:29:51 +03:00
|
|
|
protobufDecodeFields(d, &pbf.Message)
|
|
|
|
})
|
|
|
|
case format.ProtoBufTypePackedRepeated:
|
|
|
|
// TODO:
|
|
|
|
case format.ProtoBufTypeFixed32:
|
|
|
|
// TODO:
|
|
|
|
case format.ProtoBufTypeSFixed32:
|
|
|
|
// TODO:
|
|
|
|
case format.ProtoBufTypeFloat:
|
|
|
|
// TODO:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func protobufDecodeFields(d *decode.D, pbm *format.ProtoBufMessage) {
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldArray("fields", func(d *decode.D) {
|
2020-06-08 03:29:51 +03:00
|
|
|
for d.BitsLeft() > 0 {
|
|
|
|
protobufDecodeField(d, pbm)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-02-18 23:10:48 +03:00
|
|
|
func protobufDecode(d *decode.D) any {
|
2023-05-01 14:19:04 +03:00
|
|
|
var pbi format.Protobuf_In
|
2023-02-18 23:10:48 +03:00
|
|
|
d.ArgAs(&pbi)
|
2020-06-08 03:29:51 +03:00
|
|
|
|
2023-02-18 23:10:48 +03:00
|
|
|
protobufDecodeFields(d, &pbi.Message)
|
2020-06-08 03:29:51 +03:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|