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 }