proto: support message_set_wire_format

MessageSets are a deprecated proto1 feature, long since superseded by
extensions. Add disabled-by-default support behind flags.Proto1Legacy.

Change-Id: I7d3ace07f3b0efd59673034f3dc633b908345a88
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/185538
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/proto/messageset.go b/proto/messageset.go
new file mode 100644
index 0000000..1c6ac29
--- /dev/null
+++ b/proto/messageset.go
@@ -0,0 +1,102 @@
+// 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.Proto1Legacy {
+		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.Proto1Legacy {
+		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
+			}
+			fd, err := o.Resolver.FindExtensionByNumber(md.FullName(), num)
+			if err == protoregistry.NotFound {
+				return errUnknown
+			}
+			if err != nil {
+				return err
+			}
+			if err := o.unmarshalMessage(v, m.Mutable(fd).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
+}