legacy_file.go raw

   1  // Copyright 2018 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package impl
   6  
   7  import (
   8  	"bytes"
   9  	"compress/gzip"
  10  	"io"
  11  	"sync"
  12  
  13  	"google.golang.org/protobuf/internal/filedesc"
  14  	"google.golang.org/protobuf/reflect/protoreflect"
  15  	"google.golang.org/protobuf/reflect/protoregistry"
  16  )
  17  
  18  // Every enum and message type generated by protoc-gen-go since commit 2fc053c5
  19  // on February 25th, 2016 has had a method to get the raw descriptor.
  20  // Types that were not generated by protoc-gen-go or were generated prior
  21  // to that version are not supported.
  22  //
  23  // The []byte returned is the encoded form of a FileDescriptorProto message
  24  // compressed using GZIP. The []int is the path from the top-level file
  25  // to the specific message or enum declaration.
  26  type (
  27  	enumV1 interface {
  28  		EnumDescriptor() ([]byte, []int)
  29  	}
  30  	messageV1 interface {
  31  		Descriptor() ([]byte, []int)
  32  	}
  33  )
  34  
  35  var legacyFileDescCache sync.Map // map[*byte]protoreflect.FileDescriptor
  36  
  37  // legacyLoadFileDesc unmarshals b as a compressed FileDescriptorProto message.
  38  //
  39  // This assumes that b is immutable and that b does not refer to part of a
  40  // concatenated series of GZIP files (which would require shenanigans that
  41  // rely on the concatenation properties of both protobufs and GZIP).
  42  // File descriptors generated by protoc-gen-go do not rely on that property.
  43  func legacyLoadFileDesc(b []byte) protoreflect.FileDescriptor {
  44  	// Fast-path: check whether we already have a cached file descriptor.
  45  	if fd, ok := legacyFileDescCache.Load(&b[0]); ok {
  46  		return fd.(protoreflect.FileDescriptor)
  47  	}
  48  
  49  	// Slow-path: decompress and unmarshal the file descriptor proto.
  50  	zr, err := gzip.NewReader(bytes.NewReader(b))
  51  	if err != nil {
  52  		panic(err)
  53  	}
  54  	b2, err := io.ReadAll(zr)
  55  	if err != nil {
  56  		panic(err)
  57  	}
  58  
  59  	fd := filedesc.Builder{
  60  		RawDescriptor: b2,
  61  		FileRegistry:  resolverOnly{protoregistry.GlobalFiles}, // do not register back to global registry
  62  	}.Build().File
  63  	if fd, ok := legacyFileDescCache.LoadOrStore(&b[0], fd); ok {
  64  		return fd.(protoreflect.FileDescriptor)
  65  	}
  66  	return fd
  67  }
  68  
  69  type resolverOnly struct {
  70  	reg *protoregistry.Files
  71  }
  72  
  73  func (r resolverOnly) FindFileByPath(path string) (protoreflect.FileDescriptor, error) {
  74  	return r.reg.FindFileByPath(path)
  75  }
  76  func (r resolverOnly) FindDescriptorByName(name protoreflect.FullName) (protoreflect.Descriptor, error) {
  77  	return r.reg.FindDescriptorByName(name)
  78  }
  79  func (resolverOnly) RegisterFile(protoreflect.FileDescriptor) error {
  80  	return nil
  81  }
  82