internal/legacy: remove dependency on descriptor.proto
We jump through many hoops to avoid generated protos depending on
internal/legacy. Break the cycle in the other direction: Remove
the dependency on descriptor.proto from internal/legacy by
using a hand-written parser for the few descriptor fields we need.
Still to do: Remove the descriptor.proto dependency from
internal/encoding/tag.
Change-Id: I5fd99a2170470ba8530eb2679b6dde899821bf3e
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/171457
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/legacy/parse.go b/internal/legacy/parse.go
new file mode 100644
index 0000000..eac1256
--- /dev/null
+++ b/internal/legacy/parse.go
@@ -0,0 +1,169 @@
+// 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 legacy
+
+import (
+ "github.com/golang/protobuf/v2/internal/encoding/wire"
+ "github.com/golang/protobuf/v2/internal/fieldnum"
+)
+
+// To avoid a dependency from legacy to descriptor.proto, use a hand-written parser
+// for the bits of the descriptor we need.
+//
+// TODO: Consider unifying this with the parser in fileinit.
+
+type fileDescriptorProto struct {
+ Syntax string
+ Package string
+ EnumType []*enumDescriptorProto
+ MessageType []*descriptorProto
+}
+
+func (fd fileDescriptorProto) GetSyntax() string { return fd.Syntax }
+func (fd fileDescriptorProto) GetPackage() string { return fd.Package }
+
+func parseFileDescProto(b []byte) *fileDescriptorProto {
+ fd := &fileDescriptorProto{}
+ for len(b) > 0 {
+ num, typ, n := wire.ConsumeTag(b)
+ parseCheck(n)
+ b = b[n:]
+ switch typ {
+ case wire.BytesType:
+ v, n := wire.ConsumeBytes(b)
+ b = b[n:]
+ switch num {
+ case fieldnum.FileDescriptorProto_Syntax:
+ fd.Syntax = string(v)
+ case fieldnum.FileDescriptorProto_Package:
+ fd.Package = string(v)
+ case fieldnum.FileDescriptorProto_EnumType:
+ fd.EnumType = append(fd.EnumType, parseEnumDescProto(v))
+ case fieldnum.FileDescriptorProto_MessageType:
+ fd.MessageType = append(fd.MessageType, parseDescProto(v))
+ }
+ default:
+ n := wire.ConsumeFieldValue(num, typ, b)
+ parseCheck(n)
+ b = b[n:]
+ }
+ }
+ return fd
+}
+
+type descriptorProto struct {
+ Name string
+ NestedType []*descriptorProto
+ EnumType []*enumDescriptorProto
+}
+
+func (md descriptorProto) GetName() string { return md.Name }
+
+func parseDescProto(b []byte) *descriptorProto {
+ md := &descriptorProto{}
+ for len(b) > 0 {
+ num, typ, n := wire.ConsumeTag(b)
+ parseCheck(n)
+ b = b[n:]
+ switch typ {
+ case wire.BytesType:
+ v, n := wire.ConsumeBytes(b)
+ parseCheck(n)
+ b = b[n:]
+ switch num {
+ case fieldnum.DescriptorProto_Name:
+ md.Name = string(v)
+ case fieldnum.DescriptorProto_NestedType:
+ md.NestedType = append(md.NestedType, parseDescProto(v))
+ case fieldnum.DescriptorProto_EnumType:
+ md.EnumType = append(md.EnumType, parseEnumDescProto(v))
+ }
+ default:
+ n := wire.ConsumeFieldValue(num, typ, b)
+ parseCheck(n)
+ b = b[n:]
+ }
+ }
+ return md
+}
+
+type enumDescriptorProto struct {
+ Name string
+ Value []*enumValueDescriptorProto
+}
+
+func (ed enumDescriptorProto) GetName() string { return ed.Name }
+
+func parseEnumDescProto(b []byte) *enumDescriptorProto {
+ ed := &enumDescriptorProto{}
+ for len(b) > 0 {
+ num, typ, n := wire.ConsumeTag(b)
+ parseCheck(n)
+ b = b[n:]
+ switch typ {
+ case wire.BytesType:
+ v, n := wire.ConsumeBytes(b)
+ parseCheck(n)
+ b = b[n:]
+ switch num {
+ case fieldnum.EnumDescriptorProto_Name:
+ ed.Name = string(v)
+ case fieldnum.EnumDescriptorProto_Value:
+ ed.Value = append(ed.Value, parseEnumValueDescProto(v))
+ }
+ default:
+ n := wire.ConsumeFieldValue(num, typ, b)
+ parseCheck(n)
+ b = b[n:]
+ }
+ }
+ return ed
+}
+
+type enumValueDescriptorProto struct {
+ Name string
+ Number int32
+}
+
+func (ed enumValueDescriptorProto) GetName() string { return ed.Name }
+func (ed enumValueDescriptorProto) GetNumber() int32 { return ed.Number }
+
+func parseEnumValueDescProto(b []byte) *enumValueDescriptorProto {
+ vd := &enumValueDescriptorProto{}
+ for len(b) > 0 {
+ num, typ, n := wire.ConsumeTag(b)
+ parseCheck(n)
+ b = b[n:]
+ switch typ {
+ case wire.VarintType:
+ v, n := wire.ConsumeVarint(b)
+ parseCheck(n)
+ b = b[n:]
+ switch num {
+ case fieldnum.EnumValueDescriptorProto_Number:
+ vd.Number = int32(v)
+ }
+ case wire.BytesType:
+ v, n := wire.ConsumeBytes(b)
+ parseCheck(n)
+ b = b[n:]
+ switch num {
+ case fieldnum.EnumDescriptorProto_Name:
+ vd.Name = string(v)
+ }
+ default:
+ n := wire.ConsumeFieldValue(num, typ, b)
+ parseCheck(n)
+ b = b[n:]
+ }
+ }
+ return vd
+}
+
+func parseCheck(n int) {
+ if n < 0 {
+ panic(wire.ParseError(n))
+ }
+}