github.com/bakjos/protoreflect@v1.9.2/internal/standard_files.go (about)

     1  // Package internal contains some code that should not be exported but needs to
     2  // be shared across more than one of the protoreflect sub-packages.
     3  package internal
     4  
     5  import (
     6  	"bytes"
     7  	"compress/gzip"
     8  	"fmt"
     9  	"io/ioutil"
    10  
    11  	"github.com/golang/protobuf/proto"
    12  	dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
    13  )
    14  
    15  // TODO: replace this alias configuration with desc.RegisterImportPath?
    16  
    17  // StdFileAliases are the standard protos included with protoc, but older versions of
    18  // their respective packages registered them using incorrect paths.
    19  var StdFileAliases = map[string]string{
    20  	// Files for the github.com/golang/protobuf/ptypes package at one point were
    21  	// registered using the path where the proto files are mirrored in GOPATH,
    22  	// inside the golang/protobuf repo.
    23  	// (Fixed as of https://github.com/golang/protobuf/pull/412)
    24  	"google/protobuf/any.proto":       "github.com/golang/protobuf/ptypes/any/any.proto",
    25  	"google/protobuf/duration.proto":  "github.com/golang/protobuf/ptypes/duration/duration.proto",
    26  	"google/protobuf/empty.proto":     "github.com/golang/protobuf/ptypes/empty/empty.proto",
    27  	"google/protobuf/struct.proto":    "github.com/golang/protobuf/ptypes/struct/struct.proto",
    28  	"google/protobuf/timestamp.proto": "github.com/golang/protobuf/ptypes/timestamp/timestamp.proto",
    29  	"google/protobuf/wrappers.proto":  "github.com/golang/protobuf/ptypes/wrappers/wrappers.proto",
    30  	// Files for the google.golang.org/genproto/protobuf package at one point
    31  	// were registered with an anomalous "src/" prefix.
    32  	// (Fixed as of https://github.com/google/go-genproto/pull/31)
    33  	"google/protobuf/api.proto":            "src/google/protobuf/api.proto",
    34  	"google/protobuf/field_mask.proto":     "src/google/protobuf/field_mask.proto",
    35  	"google/protobuf/source_context.proto": "src/google/protobuf/source_context.proto",
    36  	"google/protobuf/type.proto":           "src/google/protobuf/type.proto",
    37  
    38  	// Other standard files (descriptor.proto and compiler/plugin.proto) are
    39  	// registered correctly, so we don't need rules for them here.
    40  }
    41  
    42  func init() {
    43  	// We provide aliasing in both directions, to support files with the
    44  	// proper import path linked against older versions of the generated
    45  	// files AND files that used the aliased import path but linked against
    46  	// newer versions of the generated files (which register with the
    47  	// correct path).
    48  
    49  	// Get all files defined above
    50  	keys := make([]string, 0, len(StdFileAliases))
    51  	for k := range StdFileAliases {
    52  		keys = append(keys, k)
    53  	}
    54  	// And add inverse mappings
    55  	for _, k := range keys {
    56  		alias := StdFileAliases[k]
    57  		StdFileAliases[alias] = k
    58  	}
    59  }
    60  
    61  type ErrNoSuchFile string
    62  
    63  func (e ErrNoSuchFile) Error() string {
    64  	return fmt.Sprintf("no such file: %q", string(e))
    65  }
    66  
    67  // LoadFileDescriptor loads a registered descriptor and decodes it. If the given
    68  // name cannot be loaded but is a known standard name, an alias will be tried,
    69  // so the standard files can be loaded even if linked against older "known bad"
    70  // versions of packages.
    71  func LoadFileDescriptor(file string) (*dpb.FileDescriptorProto, error) {
    72  	fdb := proto.FileDescriptor(file)
    73  	aliased := false
    74  	if fdb == nil {
    75  		var ok bool
    76  		alias, ok := StdFileAliases[file]
    77  		if ok {
    78  			aliased = true
    79  			if fdb = proto.FileDescriptor(alias); fdb == nil {
    80  				return nil, ErrNoSuchFile(file)
    81  			}
    82  		} else {
    83  			return nil, ErrNoSuchFile(file)
    84  		}
    85  	}
    86  
    87  	fd, err := DecodeFileDescriptor(file, fdb)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	if aliased {
    93  		// the file descriptor will have the alias used to load it, but
    94  		// we need it to have the specified name in order to link it
    95  		fd.Name = proto.String(file)
    96  	}
    97  
    98  	return fd, nil
    99  }
   100  
   101  // DecodeFileDescriptor decodes the bytes of a registered file descriptor.
   102  // Registered file descriptors are first "proto encoded" (e.g. binary format
   103  // for the descriptor protos) and then gzipped. So this function gunzips and
   104  // then unmarshals into a descriptor proto.
   105  func DecodeFileDescriptor(element string, fdb []byte) (*dpb.FileDescriptorProto, error) {
   106  	raw, err := decompress(fdb)
   107  	if err != nil {
   108  		return nil, fmt.Errorf("failed to decompress %q descriptor: %v", element, err)
   109  	}
   110  	fd := dpb.FileDescriptorProto{}
   111  	if err := proto.Unmarshal(raw, &fd); err != nil {
   112  		return nil, fmt.Errorf("bad descriptor for %q: %v", element, err)
   113  	}
   114  	return &fd, nil
   115  }
   116  
   117  func decompress(b []byte) ([]byte, error) {
   118  	r, err := gzip.NewReader(bytes.NewReader(b))
   119  	if err != nil {
   120  		return nil, fmt.Errorf("bad gzipped descriptor: %v", err)
   121  	}
   122  	out, err := ioutil.ReadAll(r)
   123  	if err != nil {
   124  		return nil, fmt.Errorf("bad gzipped descriptor: %v", err)
   125  	}
   126  	return out, nil
   127  }