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/file.go b/internal/legacy/file.go
index f4984c8..0f871a0 100644
--- a/internal/legacy/file.go
+++ b/internal/legacy/file.go
@@ -10,9 +10,7 @@
 	"io/ioutil"
 	"sync"
 
-	"github.com/golang/protobuf/v2/proto"
 	pref "github.com/golang/protobuf/v2/reflect/protoreflect"
-	descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
 )
 
 // Every enum and message type generated by protoc-gen-go since commit 2fc053c5
@@ -34,22 +32,19 @@
 
 var fileDescCache sync.Map // map[*byte]*descriptorpb.FileDescriptorProto
 
-// LoadFileDesc unmarshals b as a compressed FileDescriptorProto message.
+// loadFileDesc unmarshals b as a compressed FileDescriptorProto message.
 //
 // This assumes that b is immutable and that b does not refer to part of a
 // concatenated series of GZIP files (which would require shenanigans that
 // rely on the concatenation properties of both protobufs and GZIP).
 // File descriptors generated by protoc-gen-go do not rely on that property.
-//
-// This is exported for testing purposes.
-func LoadFileDesc(b []byte) *descriptorpb.FileDescriptorProto {
+func loadFileDesc(b []byte) *fileDescriptorProto {
 	// Fast-path: check whether we already have a cached file descriptor.
 	if fd, ok := fileDescCache.Load(&b[0]); ok {
-		return fd.(*descriptorpb.FileDescriptorProto)
+		return fd.(*fileDescriptorProto)
 	}
 
 	// Slow-path: decompress and unmarshal the file descriptor proto.
-	fd := new(descriptorpb.FileDescriptorProto)
 	zr, err := gzip.NewReader(bytes.NewReader(b))
 	if err != nil {
 		panic(err)
@@ -58,12 +53,9 @@
 	if err != nil {
 		panic(err)
 	}
-	err = proto.UnmarshalOptions{DiscardUnknown: true}.Unmarshal(b, fd)
-	if err != nil {
-		panic(err)
-	}
+	fd := parseFileDescProto(b)
 	if fd, ok := fileDescCache.LoadOrStore(&b[0], fd); ok {
-		return fd.(*descriptorpb.FileDescriptorProto)
+		return fd.(*fileDescriptorProto)
 	}
 	return fd
 }