blob: 4a8b47a93f41779c9ac0733f29f4bd3cc30b7299 [file] [log] [blame]
khenaidooefff76e2021-12-15 16:51:30 -05001// 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.
3package internal
4
5import (
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.
19var 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
42func 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
61type ErrNoSuchFile string
62
63func (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.
71func 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.
105func 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
117func 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}