protobuf-go/proto/messageset.go
Joe Tsai 1799d1111a all: rename tag and flags for legacy support
Rename build tag "proto1_legacy" -> "protolegacy"
to be consistent with the "protoreflect" tag.

Rename flag constant "Proto1Legacy" -> "ProtoLegacy" since
it covers more than simply proto1 legacy features.
For example, it covers alpha-features of proto3 that
were eventually removed from the final proto3 release.

Change-Id: I0f4fcbadd4b5a61c87645e2e5be11d187e59157c
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189345
Reviewed-by: Damien Neil <dneil@google.com>
2019-08-08 20:49:00 +00:00

104 lines
2.9 KiB
Go

// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style.
// license that can be found in the LICENSE file.
package proto
import (
"google.golang.org/protobuf/internal/encoding/messageset"
"google.golang.org/protobuf/internal/encoding/wire"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/flags"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
func sizeMessageSet(m protoreflect.Message) (size int) {
m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
size += messageset.SizeField(fd.Number())
size += wire.SizeTag(messageset.FieldMessage)
size += wire.SizeBytes(sizeMessage(v.Message()))
return true
})
size += len(m.GetUnknown())
return size
}
func marshalMessageSet(b []byte, m protoreflect.Message, o MarshalOptions) ([]byte, error) {
if !flags.ProtoLegacy {
return b, errors.New("no support for message_set_wire_format")
}
var err error
o.rangeFields(m, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
b, err = marshalMessageSetField(b, fd, v, o)
return err == nil
})
if err != nil {
return b, err
}
b = append(b, m.GetUnknown()...)
return b, nil
}
func marshalMessageSetField(b []byte, fd protoreflect.FieldDescriptor, value protoreflect.Value, o MarshalOptions) ([]byte, error) {
b = messageset.AppendFieldStart(b, fd.Number())
b = wire.AppendTag(b, messageset.FieldMessage, wire.BytesType)
b = wire.AppendVarint(b, uint64(o.Size(value.Message().Interface())))
b, err := o.marshalMessage(b, value.Message())
if err != nil {
return b, err
}
b = messageset.AppendFieldEnd(b)
return b, nil
}
func unmarshalMessageSet(b []byte, m protoreflect.Message, o UnmarshalOptions) error {
if !flags.ProtoLegacy {
return errors.New("no support for message_set_wire_format")
}
md := m.Descriptor()
for len(b) > 0 {
err := func() error {
num, v, n, err := messageset.ConsumeField(b)
if err != nil {
// Not a message set field.
//
// Return errUnknown to try to add this to the unknown fields.
// If the field is completely unparsable, we'll catch it
// when trying to skip the field.
return errUnknown
}
if !md.ExtensionRanges().Has(num) {
return errUnknown
}
xt, err := o.Resolver.FindExtensionByNumber(md.FullName(), num)
if err == protoregistry.NotFound {
return errUnknown
}
if err != nil {
return err
}
xd := xt.Descriptor()
if err := o.unmarshalMessage(v, m.Mutable(xd).Message()); err != nil {
// Contents cannot be unmarshaled.
return err
}
b = b[n:]
return nil
}()
if err == errUnknown {
_, _, n := wire.ConsumeField(b)
if n < 0 {
return wire.ParseError(n)
}
m.SetUnknown(append(m.GetUnknown(), b[:n]...))
b = b[n:]
continue
}
if err != nil {
return err
}
}
return nil
}