1// Copyright 2019 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
5package filedesc
6
7import (
8 "fmt"
9 "sync"
10
11 "google.golang.org/protobuf/encoding/protowire"
12 "google.golang.org/protobuf/internal/genid"
13 "google.golang.org/protobuf/internal/strs"
14 "google.golang.org/protobuf/reflect/protoreflect"
15)
16
17// fileRaw is a data struct used when initializing a file descriptor from
18// a raw FileDescriptorProto.
19type fileRaw struct {
20 builder Builder
21 allEnums []Enum
22 allMessages []Message
23 allExtensions []Extension
24 allServices []Service
25}
26
27func newRawFile(db Builder) *File {
28 fd := &File{fileRaw: fileRaw{builder: db}}
29 fd.initDecls(db.NumEnums, db.NumMessages, db.NumExtensions, db.NumServices)
30 fd.unmarshalSeed(db.RawDescriptor)
31
32 // Extended message targets are eagerly resolved since registration
33 // needs this information at program init time.
34 for i := range fd.allExtensions {
35 xd := &fd.allExtensions[i]
36 xd.L1.Extendee = fd.resolveMessageDependency(xd.L1.Extendee, listExtTargets, int32(i))
37 }
38
39 fd.checkDecls()
40 return fd
41}
42
43// initDecls pre-allocates slices for the exact number of enums, messages
44// (including map entries), extensions, and services declared in the proto file.
45// This is done to avoid regrowing the slice, which would change the address
46// for any previously seen declaration.
47//
48// The alloc methods "allocates" slices by pulling from the capacity.
49func (fd *File) initDecls(numEnums, numMessages, numExtensions, numServices int32) {
50 fd.allEnums = make([]Enum, 0, numEnums)
51 fd.allMessages = make([]Message, 0, numMessages)
52 fd.allExtensions = make([]Extension, 0, numExtensions)
53 fd.allServices = make([]Service, 0, numServices)
54}
55
56func (fd *File) allocEnums(n int) []Enum {
57 total := len(fd.allEnums)
58 es := fd.allEnums[total : total+n]
59 fd.allEnums = fd.allEnums[:total+n]
60 return es
61}
62func (fd *File) allocMessages(n int) []Message {
63 total := len(fd.allMessages)
64 ms := fd.allMessages[total : total+n]
65 fd.allMessages = fd.allMessages[:total+n]
66 return ms
67}
68func (fd *File) allocExtensions(n int) []Extension {
69 total := len(fd.allExtensions)
70 xs := fd.allExtensions[total : total+n]
71 fd.allExtensions = fd.allExtensions[:total+n]
72 return xs
73}
74func (fd *File) allocServices(n int) []Service {
75 total := len(fd.allServices)
76 xs := fd.allServices[total : total+n]
77 fd.allServices = fd.allServices[:total+n]
78 return xs
79}
80
81// checkDecls performs a sanity check that the expected number of expected
82// declarations matches the number that were found in the descriptor proto.
83func (fd *File) checkDecls() {
84 switch {
85 case len(fd.allEnums) != cap(fd.allEnums):
86 case len(fd.allMessages) != cap(fd.allMessages):
87 case len(fd.allExtensions) != cap(fd.allExtensions):
88 case len(fd.allServices) != cap(fd.allServices):
89 default:
90 return
91 }
92 panic("mismatching cardinality")
93}
94
95func (fd *File) unmarshalSeed(b []byte) {
96 sb := getBuilder()
97 defer putBuilder(sb)
98
99 var prevField protoreflect.FieldNumber
100 var numEnums, numMessages, numExtensions, numServices int
101 var posEnums, posMessages, posExtensions, posServices int
102 var options []byte
103 b0 := b
104 for len(b) > 0 {
105 num, typ, n := protowire.ConsumeTag(b)
106 b = b[n:]
107 switch typ {
108 case protowire.BytesType:
109 v, m := protowire.ConsumeBytes(b)
110 b = b[m:]
111 switch num {
112 case genid.FileDescriptorProto_Syntax_field_number:
113 switch string(v) {
114 case "proto2":
115 fd.L1.Syntax = protoreflect.Proto2
116 fd.L1.Edition = EditionProto2
117 case "proto3":
118 fd.L1.Syntax = protoreflect.Proto3
119 fd.L1.Edition = EditionProto3
120 case "editions":
121 fd.L1.Syntax = protoreflect.Editions
122 default:
123 panic("invalid syntax")
124 }
125 case genid.FileDescriptorProto_Name_field_number:
126 fd.L1.Path = sb.MakeString(v)
127 case genid.FileDescriptorProto_Package_field_number:
128 fd.L1.Package = protoreflect.FullName(sb.MakeString(v))
129 case genid.FileDescriptorProto_Options_field_number:
130 options = v
131 case genid.FileDescriptorProto_EnumType_field_number:
132 if prevField != genid.FileDescriptorProto_EnumType_field_number {
133 if numEnums > 0 {
134 panic("non-contiguous repeated field")
135 }
136 posEnums = len(b0) - len(b) - n - m
137 }
138 numEnums++
139 case genid.FileDescriptorProto_MessageType_field_number:
140 if prevField != genid.FileDescriptorProto_MessageType_field_number {
141 if numMessages > 0 {
142 panic("non-contiguous repeated field")
143 }
144 posMessages = len(b0) - len(b) - n - m
145 }
146 numMessages++
147 case genid.FileDescriptorProto_Extension_field_number:
148 if prevField != genid.FileDescriptorProto_Extension_field_number {
149 if numExtensions > 0 {
150 panic("non-contiguous repeated field")
151 }
152 posExtensions = len(b0) - len(b) - n - m
153 }
154 numExtensions++
155 case genid.FileDescriptorProto_Service_field_number:
156 if prevField != genid.FileDescriptorProto_Service_field_number {
157 if numServices > 0 {
158 panic("non-contiguous repeated field")
159 }
160 posServices = len(b0) - len(b) - n - m
161 }
162 numServices++
163 }
164 prevField = num
165 case protowire.VarintType:
166 v, m := protowire.ConsumeVarint(b)
167 b = b[m:]
168 switch num {
169 case genid.FileDescriptorProto_Edition_field_number:
170 fd.L1.Edition = Edition(v)
171 }
172 default:
173 m := protowire.ConsumeFieldValue(num, typ, b)
174 b = b[m:]
175 prevField = -1 // ignore known field numbers of unknown wire type
176 }
177 }
178
179 // If syntax is missing, it is assumed to be proto2.
180 if fd.L1.Syntax == 0 {
181 fd.L1.Syntax = protoreflect.Proto2
182 fd.L1.Edition = EditionProto2
183 }
184
185 fd.L1.EditionFeatures = getFeaturesFor(fd.L1.Edition)
186
187 // Parse editions features from options if any
188 if options != nil {
189 fd.unmarshalSeedOptions(options)
190 }
191
192 // Must allocate all declarations before parsing each descriptor type
193 // to ensure we handled all descriptors in "flattened ordering".
194 if numEnums > 0 {
195 fd.L1.Enums.List = fd.allocEnums(numEnums)
196 }
197 if numMessages > 0 {
198 fd.L1.Messages.List = fd.allocMessages(numMessages)
199 }
200 if numExtensions > 0 {
201 fd.L1.Extensions.List = fd.allocExtensions(numExtensions)
202 }
203 if numServices > 0 {
204 fd.L1.Services.List = fd.allocServices(numServices)
205 }
206
207 if numEnums > 0 {
208 b := b0[posEnums:]
209 for i := range fd.L1.Enums.List {
210 _, n := protowire.ConsumeVarint(b)
211 v, m := protowire.ConsumeBytes(b[n:])
212 fd.L1.Enums.List[i].unmarshalSeed(v, sb, fd, fd, i)
213 b = b[n+m:]
214 }
215 }
216 if numMessages > 0 {
217 b := b0[posMessages:]
218 for i := range fd.L1.Messages.List {
219 _, n := protowire.ConsumeVarint(b)
220 v, m := protowire.ConsumeBytes(b[n:])
221 fd.L1.Messages.List[i].unmarshalSeed(v, sb, fd, fd, i)
222 b = b[n+m:]
223 }
224 }
225 if numExtensions > 0 {
226 b := b0[posExtensions:]
227 for i := range fd.L1.Extensions.List {
228 _, n := protowire.ConsumeVarint(b)
229 v, m := protowire.ConsumeBytes(b[n:])
230 fd.L1.Extensions.List[i].unmarshalSeed(v, sb, fd, fd, i)
231 b = b[n+m:]
232 }
233 }
234 if numServices > 0 {
235 b := b0[posServices:]
236 for i := range fd.L1.Services.List {
237 _, n := protowire.ConsumeVarint(b)
238 v, m := protowire.ConsumeBytes(b[n:])
239 fd.L1.Services.List[i].unmarshalSeed(v, sb, fd, fd, i)
240 b = b[n+m:]
241 }
242 }
243}
244
245func (fd *File) unmarshalSeedOptions(b []byte) {
246 for b := b; len(b) > 0; {
247 num, typ, n := protowire.ConsumeTag(b)
248 b = b[n:]
249 switch typ {
250 case protowire.BytesType:
251 v, m := protowire.ConsumeBytes(b)
252 b = b[m:]
253 switch num {
254 case genid.FileOptions_Features_field_number:
255 if fd.Syntax() != protoreflect.Editions {
256 panic(fmt.Sprintf("invalid descriptor: using edition features in a proto with syntax %s", fd.Syntax()))
257 }
258 fd.L1.EditionFeatures = unmarshalFeatureSet(v, fd.L1.EditionFeatures)
259 }
260 default:
261 m := protowire.ConsumeFieldValue(num, typ, b)
262 b = b[m:]
263 }
264 }
265}
266
267func (ed *Enum) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protoreflect.Descriptor, i int) {
268 ed.L0.ParentFile = pf
269 ed.L0.Parent = pd
270 ed.L0.Index = i
271 ed.L1.EditionFeatures = featuresFromParentDesc(ed.Parent())
272
273 var numValues int
274 for b := b; len(b) > 0; {
275 num, typ, n := protowire.ConsumeTag(b)
276 b = b[n:]
277 switch typ {
278 case protowire.BytesType:
279 v, m := protowire.ConsumeBytes(b)
280 b = b[m:]
281 switch num {
282 case genid.EnumDescriptorProto_Name_field_number:
283 ed.L0.FullName = appendFullName(sb, pd.FullName(), v)
284 case genid.EnumDescriptorProto_Value_field_number:
285 numValues++
286 }
287 default:
288 m := protowire.ConsumeFieldValue(num, typ, b)
289 b = b[m:]
290 }
291 }
292
293 // Only construct enum value descriptors for top-level enums since
294 // they are needed for registration.
295 if pd != pf {
296 return
297 }
298 ed.L1.eagerValues = true
299 ed.L2 = new(EnumL2)
300 ed.L2.Values.List = make([]EnumValue, numValues)
301 for i := 0; len(b) > 0; {
302 num, typ, n := protowire.ConsumeTag(b)
303 b = b[n:]
304 switch typ {
305 case protowire.BytesType:
306 v, m := protowire.ConsumeBytes(b)
307 b = b[m:]
308 switch num {
309 case genid.EnumDescriptorProto_Value_field_number:
310 ed.L2.Values.List[i].unmarshalFull(v, sb, pf, ed, i)
311 i++
312 }
313 default:
314 m := protowire.ConsumeFieldValue(num, typ, b)
315 b = b[m:]
316 }
317 }
318}
319
320func (md *Message) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protoreflect.Descriptor, i int) {
321 md.L0.ParentFile = pf
322 md.L0.Parent = pd
323 md.L0.Index = i
324 md.L1.EditionFeatures = featuresFromParentDesc(md.Parent())
325
326 var prevField protoreflect.FieldNumber
327 var numEnums, numMessages, numExtensions int
328 var posEnums, posMessages, posExtensions int
329 b0 := b
330 for len(b) > 0 {
331 num, typ, n := protowire.ConsumeTag(b)
332 b = b[n:]
333 switch typ {
334 case protowire.BytesType:
335 v, m := protowire.ConsumeBytes(b)
336 b = b[m:]
337 switch num {
338 case genid.DescriptorProto_Name_field_number:
339 md.L0.FullName = appendFullName(sb, pd.FullName(), v)
340 case genid.DescriptorProto_EnumType_field_number:
341 if prevField != genid.DescriptorProto_EnumType_field_number {
342 if numEnums > 0 {
343 panic("non-contiguous repeated field")
344 }
345 posEnums = len(b0) - len(b) - n - m
346 }
347 numEnums++
348 case genid.DescriptorProto_NestedType_field_number:
349 if prevField != genid.DescriptorProto_NestedType_field_number {
350 if numMessages > 0 {
351 panic("non-contiguous repeated field")
352 }
353 posMessages = len(b0) - len(b) - n - m
354 }
355 numMessages++
356 case genid.DescriptorProto_Extension_field_number:
357 if prevField != genid.DescriptorProto_Extension_field_number {
358 if numExtensions > 0 {
359 panic("non-contiguous repeated field")
360 }
361 posExtensions = len(b0) - len(b) - n - m
362 }
363 numExtensions++
364 case genid.DescriptorProto_Options_field_number:
365 md.unmarshalSeedOptions(v)
366 }
367 prevField = num
368 default:
369 m := protowire.ConsumeFieldValue(num, typ, b)
370 b = b[m:]
371 prevField = -1 // ignore known field numbers of unknown wire type
372 }
373 }
374
375 // Must allocate all declarations before parsing each descriptor type
376 // to ensure we handled all descriptors in "flattened ordering".
377 if numEnums > 0 {
378 md.L1.Enums.List = pf.allocEnums(numEnums)
379 }
380 if numMessages > 0 {
381 md.L1.Messages.List = pf.allocMessages(numMessages)
382 }
383 if numExtensions > 0 {
384 md.L1.Extensions.List = pf.allocExtensions(numExtensions)
385 }
386
387 if numEnums > 0 {
388 b := b0[posEnums:]
389 for i := range md.L1.Enums.List {
390 _, n := protowire.ConsumeVarint(b)
391 v, m := protowire.ConsumeBytes(b[n:])
392 md.L1.Enums.List[i].unmarshalSeed(v, sb, pf, md, i)
393 b = b[n+m:]
394 }
395 }
396 if numMessages > 0 {
397 b := b0[posMessages:]
398 for i := range md.L1.Messages.List {
399 _, n := protowire.ConsumeVarint(b)
400 v, m := protowire.ConsumeBytes(b[n:])
401 md.L1.Messages.List[i].unmarshalSeed(v, sb, pf, md, i)
402 b = b[n+m:]
403 }
404 }
405 if numExtensions > 0 {
406 b := b0[posExtensions:]
407 for i := range md.L1.Extensions.List {
408 _, n := protowire.ConsumeVarint(b)
409 v, m := protowire.ConsumeBytes(b[n:])
410 md.L1.Extensions.List[i].unmarshalSeed(v, sb, pf, md, i)
411 b = b[n+m:]
412 }
413 }
414}
415
416func (md *Message) unmarshalSeedOptions(b []byte) {
417 for len(b) > 0 {
418 num, typ, n := protowire.ConsumeTag(b)
419 b = b[n:]
420 switch typ {
421 case protowire.VarintType:
422 v, m := protowire.ConsumeVarint(b)
423 b = b[m:]
424 switch num {
425 case genid.MessageOptions_MapEntry_field_number:
426 md.L1.IsMapEntry = protowire.DecodeBool(v)
427 case genid.MessageOptions_MessageSetWireFormat_field_number:
428 md.L1.IsMessageSet = protowire.DecodeBool(v)
429 }
430 case protowire.BytesType:
431 v, m := protowire.ConsumeBytes(b)
432 b = b[m:]
433 switch num {
434 case genid.MessageOptions_Features_field_number:
435 md.L1.EditionFeatures = unmarshalFeatureSet(v, md.L1.EditionFeatures)
436 }
437 default:
438 m := protowire.ConsumeFieldValue(num, typ, b)
439 b = b[m:]
440 }
441 }
442}
443
444func (xd *Extension) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protoreflect.Descriptor, i int) {
445 xd.L0.ParentFile = pf
446 xd.L0.Parent = pd
447 xd.L0.Index = i
448 xd.L1.EditionFeatures = featuresFromParentDesc(pd)
449
450 for len(b) > 0 {
451 num, typ, n := protowire.ConsumeTag(b)
452 b = b[n:]
453 switch typ {
454 case protowire.VarintType:
455 v, m := protowire.ConsumeVarint(b)
456 b = b[m:]
457 switch num {
458 case genid.FieldDescriptorProto_Number_field_number:
459 xd.L1.Number = protoreflect.FieldNumber(v)
460 case genid.FieldDescriptorProto_Label_field_number:
461 xd.L1.Cardinality = protoreflect.Cardinality(v)
462 case genid.FieldDescriptorProto_Type_field_number:
463 xd.L1.Kind = protoreflect.Kind(v)
464 }
465 case protowire.BytesType:
466 v, m := protowire.ConsumeBytes(b)
467 b = b[m:]
468 switch num {
469 case genid.FieldDescriptorProto_Name_field_number:
470 xd.L0.FullName = appendFullName(sb, pd.FullName(), v)
471 case genid.FieldDescriptorProto_Extendee_field_number:
472 xd.L1.Extendee = PlaceholderMessage(makeFullName(sb, v))
473 case genid.FieldDescriptorProto_Options_field_number:
474 xd.unmarshalOptions(v)
475 }
476 default:
477 m := protowire.ConsumeFieldValue(num, typ, b)
478 b = b[m:]
479 }
480 }
481
482 if xd.L1.Kind == protoreflect.MessageKind && xd.L1.EditionFeatures.IsDelimitedEncoded {
483 xd.L1.Kind = protoreflect.GroupKind
484 }
485}
486
487func (xd *Extension) unmarshalOptions(b []byte) {
488 for len(b) > 0 {
489 num, typ, n := protowire.ConsumeTag(b)
490 b = b[n:]
491 switch typ {
492 case protowire.VarintType:
493 v, m := protowire.ConsumeVarint(b)
494 b = b[m:]
495 switch num {
496 case genid.FieldOptions_Packed_field_number:
497 xd.L1.EditionFeatures.IsPacked = protowire.DecodeBool(v)
498 case genid.FieldOptions_Lazy_field_number:
499 xd.L1.IsLazy = protowire.DecodeBool(v)
500 }
501 case protowire.BytesType:
502 v, m := protowire.ConsumeBytes(b)
503 b = b[m:]
504 switch num {
505 case genid.FieldOptions_Features_field_number:
506 xd.L1.EditionFeatures = unmarshalFeatureSet(v, xd.L1.EditionFeatures)
507 }
508 default:
509 m := protowire.ConsumeFieldValue(num, typ, b)
510 b = b[m:]
511 }
512 }
513}
514
515func (sd *Service) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protoreflect.Descriptor, i int) {
516 sd.L0.ParentFile = pf
517 sd.L0.Parent = pd
518 sd.L0.Index = i
519
520 for len(b) > 0 {
521 num, typ, n := protowire.ConsumeTag(b)
522 b = b[n:]
523 switch typ {
524 case protowire.BytesType:
525 v, m := protowire.ConsumeBytes(b)
526 b = b[m:]
527 switch num {
528 case genid.ServiceDescriptorProto_Name_field_number:
529 sd.L0.FullName = appendFullName(sb, pd.FullName(), v)
530 }
531 default:
532 m := protowire.ConsumeFieldValue(num, typ, b)
533 b = b[m:]
534 }
535 }
536}
537
538var nameBuilderPool = sync.Pool{
539 New: func() any { return new(strs.Builder) },
540}
541
542func getBuilder() *strs.Builder {
543 return nameBuilderPool.Get().(*strs.Builder)
544}
545func putBuilder(b *strs.Builder) {
546 nameBuilderPool.Put(b)
547}
548
549// makeFullName converts b to a protoreflect.FullName,
550// where b must start with a leading dot.
551func makeFullName(sb *strs.Builder, b []byte) protoreflect.FullName {
552 if len(b) == 0 || b[0] != '.' {
553 panic("name reference must be fully qualified")
554 }
555 return protoreflect.FullName(sb.MakeString(b[1:]))
556}
557
558func appendFullName(sb *strs.Builder, prefix protoreflect.FullName, suffix []byte) protoreflect.FullName {
559 return sb.AppendFullName(prefix, protoreflect.Name(strs.UnsafeString(suffix)))
560}