// Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package filedesc import ( "reflect" "sync" "google.golang.org/protobuf/encoding/protowire" "google.golang.org/protobuf/internal/descopts" "google.golang.org/protobuf/internal/fieldnum" "google.golang.org/protobuf/internal/strs" "google.golang.org/protobuf/proto" pref "google.golang.org/protobuf/reflect/protoreflect" ) func (fd *File) lazyRawInit() { fd.unmarshalFull(fd.builder.RawDescriptor) fd.resolveMessages() fd.resolveExtensions() fd.resolveServices() } func (file *File) resolveMessages() { var depIdx int32 for i := range file.allMessages { md := &file.allMessages[i] // Resolve message field dependencies. for j := range md.L2.Fields.List { fd := &md.L2.Fields.List[j] // Weak fields are resolved upon actual use. if fd.L1.IsWeak { continue } // Resolve message field dependency. switch fd.L1.Kind { case pref.EnumKind: fd.L1.Enum = file.resolveEnumDependency(fd.L1.Enum, listFieldDeps, depIdx) depIdx++ case pref.MessageKind, pref.GroupKind: fd.L1.Message = file.resolveMessageDependency(fd.L1.Message, listFieldDeps, depIdx) depIdx++ } // Default is resolved here since it depends on Enum being resolved. if v := fd.L1.Default.val; v.IsValid() { fd.L1.Default = unmarshalDefault(v.Bytes(), fd.L1.Kind, file, fd.L1.Enum) } } } } func (file *File) resolveExtensions() { var depIdx int32 for i := range file.allExtensions { xd := &file.allExtensions[i] // Resolve extension field dependency. switch xd.L1.Kind { case pref.EnumKind: xd.L2.Enum = file.resolveEnumDependency(xd.L2.Enum, listExtDeps, depIdx) depIdx++ case pref.MessageKind, pref.GroupKind: xd.L2.Message = file.resolveMessageDependency(xd.L2.Message, listExtDeps, depIdx) depIdx++ } // Default is resolved here since it depends on Enum being resolved. if v := xd.L2.Default.val; v.IsValid() { xd.L2.Default = unmarshalDefault(v.Bytes(), xd.L1.Kind, file, xd.L2.Enum) } } } func (file *File) resolveServices() { var depIdx int32 for i := range file.allServices { sd := &file.allServices[i] // Resolve method dependencies. for j := range sd.L2.Methods.List { md := &sd.L2.Methods.List[j] md.L1.Input = file.resolveMessageDependency(md.L1.Input, listMethInDeps, depIdx) md.L1.Output = file.resolveMessageDependency(md.L1.Output, listMethOutDeps, depIdx) depIdx++ } } } func (file *File) resolveEnumDependency(ed pref.EnumDescriptor, i, j int32) pref.EnumDescriptor { r := file.builder.FileRegistry if r, ok := r.(resolverByIndex); ok { if ed2 := r.FindEnumByIndex(i, j, file.allEnums, file.allMessages); ed2 != nil { return ed2 } } for i := range file.allEnums { if ed2 := &file.allEnums[i]; ed2.L0.FullName == ed.FullName() { return ed2 } } if d, _ := r.FindDescriptorByName(ed.FullName()); d != nil { return d.(pref.EnumDescriptor) } return ed } func (file *File) resolveMessageDependency(md pref.MessageDescriptor, i, j int32) pref.MessageDescriptor { r := file.builder.FileRegistry if r, ok := r.(resolverByIndex); ok { if md2 := r.FindMessageByIndex(i, j, file.allEnums, file.allMessages); md2 != nil { return md2 } } for i := range file.allMessages { if md2 := &file.allMessages[i]; md2.L0.FullName == md.FullName() { return md2 } } if d, _ := r.FindDescriptorByName(md.FullName()); d != nil { return d.(pref.MessageDescriptor) } return md } func (fd *File) unmarshalFull(b []byte) { sb := getBuilder() defer putBuilder(sb) var enumIdx, messageIdx, extensionIdx, serviceIdx int var rawOptions []byte fd.L2 = new(FileL2) for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.VarintType: v, m := protowire.ConsumeVarint(b) b = b[m:] switch num { case fieldnum.FileDescriptorProto_PublicDependency: fd.L2.Imports[v].IsPublic = true case fieldnum.FileDescriptorProto_WeakDependency: fd.L2.Imports[v].IsWeak = true } case protowire.BytesType: v, m := protowire.ConsumeBytes(b) b = b[m:] switch num { case fieldnum.FileDescriptorProto_Dependency: path := sb.MakeString(v) imp, _ := fd.builder.FileRegistry.FindFileByPath(path) if imp == nil { imp = PlaceholderFile(path) } fd.L2.Imports = append(fd.L2.Imports, pref.FileImport{FileDescriptor: imp}) case fieldnum.FileDescriptorProto_EnumType: fd.L1.Enums.List[enumIdx].unmarshalFull(v, sb) enumIdx++ case fieldnum.FileDescriptorProto_MessageType: fd.L1.Messages.List[messageIdx].unmarshalFull(v, sb) messageIdx++ case fieldnum.FileDescriptorProto_Extension: fd.L1.Extensions.List[extensionIdx].unmarshalFull(v, sb) extensionIdx++ case fieldnum.FileDescriptorProto_Service: fd.L1.Services.List[serviceIdx].unmarshalFull(v, sb) serviceIdx++ case fieldnum.FileDescriptorProto_Options: rawOptions = appendOptions(rawOptions, v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } fd.L2.Options = fd.builder.optionsUnmarshaler(&descopts.File, rawOptions) } func (ed *Enum) unmarshalFull(b []byte, sb *strs.Builder) { var rawValues [][]byte var rawOptions []byte if !ed.L1.eagerValues { ed.L2 = new(EnumL2) } for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.BytesType: v, m := protowire.ConsumeBytes(b) b = b[m:] switch num { case fieldnum.EnumDescriptorProto_Value: rawValues = append(rawValues, v) case fieldnum.EnumDescriptorProto_ReservedName: ed.L2.ReservedNames.List = append(ed.L2.ReservedNames.List, pref.Name(sb.MakeString(v))) case fieldnum.EnumDescriptorProto_ReservedRange: ed.L2.ReservedRanges.List = append(ed.L2.ReservedRanges.List, unmarshalEnumReservedRange(v)) case fieldnum.EnumDescriptorProto_Options: rawOptions = appendOptions(rawOptions, v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } if !ed.L1.eagerValues && len(rawValues) > 0 { ed.L2.Values.List = make([]EnumValue, len(rawValues)) for i, b := range rawValues { ed.L2.Values.List[i].unmarshalFull(b, sb, ed.L0.ParentFile, ed, i) } } ed.L2.Options = ed.L0.ParentFile.builder.optionsUnmarshaler(&descopts.Enum, rawOptions) } func unmarshalEnumReservedRange(b []byte) (r [2]pref.EnumNumber) { for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.VarintType: v, m := protowire.ConsumeVarint(b) b = b[m:] switch num { case fieldnum.EnumDescriptorProto_EnumReservedRange_Start: r[0] = pref.EnumNumber(v) case fieldnum.EnumDescriptorProto_EnumReservedRange_End: r[1] = pref.EnumNumber(v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } return r } func (vd *EnumValue) unmarshalFull(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) { vd.L0.ParentFile = pf vd.L0.Parent = pd vd.L0.Index = i var rawOptions []byte for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.VarintType: v, m := protowire.ConsumeVarint(b) b = b[m:] switch num { case fieldnum.EnumValueDescriptorProto_Number: vd.L1.Number = pref.EnumNumber(v) } case protowire.BytesType: v, m := protowire.ConsumeBytes(b) b = b[m:] switch num { case fieldnum.EnumValueDescriptorProto_Name: // NOTE: Enum values are in the same scope as the enum parent. vd.L0.FullName = appendFullName(sb, pd.Parent().FullName(), v) case fieldnum.EnumValueDescriptorProto_Options: rawOptions = appendOptions(rawOptions, v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } vd.L1.Options = pf.builder.optionsUnmarshaler(&descopts.EnumValue, rawOptions) } func (md *Message) unmarshalFull(b []byte, sb *strs.Builder) { var rawFields, rawOneofs [][]byte var enumIdx, messageIdx, extensionIdx int var rawOptions []byte md.L2 = new(MessageL2) for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.BytesType: v, m := protowire.ConsumeBytes(b) b = b[m:] switch num { case fieldnum.DescriptorProto_Field: rawFields = append(rawFields, v) case fieldnum.DescriptorProto_OneofDecl: rawOneofs = append(rawOneofs, v) case fieldnum.DescriptorProto_ReservedName: md.L2.ReservedNames.List = append(md.L2.ReservedNames.List, pref.Name(sb.MakeString(v))) case fieldnum.DescriptorProto_ReservedRange: md.L2.ReservedRanges.List = append(md.L2.ReservedRanges.List, unmarshalMessageReservedRange(v)) case fieldnum.DescriptorProto_ExtensionRange: r, rawOptions := unmarshalMessageExtensionRange(v) opts := md.L0.ParentFile.builder.optionsUnmarshaler(&descopts.ExtensionRange, rawOptions) md.L2.ExtensionRanges.List = append(md.L2.ExtensionRanges.List, r) md.L2.ExtensionRangeOptions = append(md.L2.ExtensionRangeOptions, opts) case fieldnum.DescriptorProto_EnumType: md.L1.Enums.List[enumIdx].unmarshalFull(v, sb) enumIdx++ case fieldnum.DescriptorProto_NestedType: md.L1.Messages.List[messageIdx].unmarshalFull(v, sb) messageIdx++ case fieldnum.DescriptorProto_Extension: md.L1.Extensions.List[extensionIdx].unmarshalFull(v, sb) extensionIdx++ case fieldnum.DescriptorProto_Options: md.unmarshalOptions(v) rawOptions = appendOptions(rawOptions, v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } if len(rawFields) > 0 || len(rawOneofs) > 0 { md.L2.Fields.List = make([]Field, len(rawFields)) md.L2.Oneofs.List = make([]Oneof, len(rawOneofs)) for i, b := range rawFields { fd := &md.L2.Fields.List[i] fd.unmarshalFull(b, sb, md.L0.ParentFile, md, i) if fd.L1.Cardinality == pref.Required { md.L2.RequiredNumbers.List = append(md.L2.RequiredNumbers.List, fd.L1.Number) } } for i, b := range rawOneofs { od := &md.L2.Oneofs.List[i] od.unmarshalFull(b, sb, md.L0.ParentFile, md, i) } } md.L2.Options = md.L0.ParentFile.builder.optionsUnmarshaler(&descopts.Message, rawOptions) } func (md *Message) unmarshalOptions(b []byte) { for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.VarintType: v, m := protowire.ConsumeVarint(b) b = b[m:] switch num { case fieldnum.MessageOptions_MapEntry: md.L1.IsMapEntry = protowire.DecodeBool(v) case fieldnum.MessageOptions_MessageSetWireFormat: md.L1.IsMessageSet = protowire.DecodeBool(v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } } func unmarshalMessageReservedRange(b []byte) (r [2]pref.FieldNumber) { for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.VarintType: v, m := protowire.ConsumeVarint(b) b = b[m:] switch num { case fieldnum.DescriptorProto_ReservedRange_Start: r[0] = pref.FieldNumber(v) case fieldnum.DescriptorProto_ReservedRange_End: r[1] = pref.FieldNumber(v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } return r } func unmarshalMessageExtensionRange(b []byte) (r [2]pref.FieldNumber, rawOptions []byte) { for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.VarintType: v, m := protowire.ConsumeVarint(b) b = b[m:] switch num { case fieldnum.DescriptorProto_ExtensionRange_Start: r[0] = pref.FieldNumber(v) case fieldnum.DescriptorProto_ExtensionRange_End: r[1] = pref.FieldNumber(v) } case protowire.BytesType: v, m := protowire.ConsumeBytes(b) b = b[m:] switch num { case fieldnum.DescriptorProto_ExtensionRange_Options: rawOptions = appendOptions(rawOptions, v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } return r, rawOptions } func (fd *Field) unmarshalFull(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) { fd.L0.ParentFile = pf fd.L0.Parent = pd fd.L0.Index = i var rawTypeName []byte var rawOptions []byte for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.VarintType: v, m := protowire.ConsumeVarint(b) b = b[m:] switch num { case fieldnum.FieldDescriptorProto_Number: fd.L1.Number = pref.FieldNumber(v) case fieldnum.FieldDescriptorProto_Label: fd.L1.Cardinality = pref.Cardinality(v) case fieldnum.FieldDescriptorProto_Type: fd.L1.Kind = pref.Kind(v) case fieldnum.FieldDescriptorProto_OneofIndex: // In Message.unmarshalFull, we allocate slices for both // the field and oneof descriptors before unmarshaling either // of them. This ensures pointers to slice elements are stable. od := &pd.(*Message).L2.Oneofs.List[v] od.L1.Fields.List = append(od.L1.Fields.List, fd) if fd.L1.ContainingOneof != nil { panic("oneof type already set") } fd.L1.ContainingOneof = od } case protowire.BytesType: v, m := protowire.ConsumeBytes(b) b = b[m:] switch num { case fieldnum.FieldDescriptorProto_Name: fd.L0.FullName = appendFullName(sb, pd.FullName(), v) case fieldnum.FieldDescriptorProto_JsonName: fd.L1.JSONName.Init(sb.MakeString(v)) case fieldnum.FieldDescriptorProto_DefaultValue: fd.L1.Default.val = pref.ValueOfBytes(v) // temporarily store as bytes; later resolved in resolveMessages case fieldnum.FieldDescriptorProto_TypeName: rawTypeName = v case fieldnum.FieldDescriptorProto_Options: fd.unmarshalOptions(v) rawOptions = appendOptions(rawOptions, v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } if rawTypeName != nil { name := makeFullName(sb, rawTypeName) switch fd.L1.Kind { case pref.EnumKind: fd.L1.Enum = PlaceholderEnum(name) case pref.MessageKind, pref.GroupKind: fd.L1.Message = PlaceholderMessage(name) } } fd.L1.Options = pf.builder.optionsUnmarshaler(&descopts.Field, rawOptions) } func (fd *Field) unmarshalOptions(b []byte) { const FieldOptions_EnforceUTF8 = 13 for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.VarintType: v, m := protowire.ConsumeVarint(b) b = b[m:] switch num { case fieldnum.FieldOptions_Packed: fd.L1.HasPacked = true fd.L1.IsPacked = protowire.DecodeBool(v) case fieldnum.FieldOptions_Weak: fd.L1.IsWeak = protowire.DecodeBool(v) case FieldOptions_EnforceUTF8: fd.L1.HasEnforceUTF8 = true fd.L1.EnforceUTF8 = protowire.DecodeBool(v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } } func (od *Oneof) unmarshalFull(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) { od.L0.ParentFile = pf od.L0.Parent = pd od.L0.Index = i var rawOptions []byte for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.BytesType: v, m := protowire.ConsumeBytes(b) b = b[m:] switch num { case fieldnum.OneofDescriptorProto_Name: od.L0.FullName = appendFullName(sb, pd.FullName(), v) case fieldnum.OneofDescriptorProto_Options: rawOptions = appendOptions(rawOptions, v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } od.L1.Options = pf.builder.optionsUnmarshaler(&descopts.Oneof, rawOptions) } func (xd *Extension) unmarshalFull(b []byte, sb *strs.Builder) { var rawTypeName []byte var rawOptions []byte xd.L2 = new(ExtensionL2) for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.BytesType: v, m := protowire.ConsumeBytes(b) b = b[m:] switch num { case fieldnum.FieldDescriptorProto_JsonName: xd.L2.JSONName.Init(sb.MakeString(v)) case fieldnum.FieldDescriptorProto_DefaultValue: xd.L2.Default.val = pref.ValueOfBytes(v) // temporarily store as bytes; later resolved in resolveExtensions case fieldnum.FieldDescriptorProto_TypeName: rawTypeName = v case fieldnum.FieldDescriptorProto_Options: xd.unmarshalOptions(v) rawOptions = appendOptions(rawOptions, v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } if rawTypeName != nil { name := makeFullName(sb, rawTypeName) switch xd.L1.Kind { case pref.EnumKind: xd.L2.Enum = PlaceholderEnum(name) case pref.MessageKind, pref.GroupKind: xd.L2.Message = PlaceholderMessage(name) } } xd.L2.Options = xd.L0.ParentFile.builder.optionsUnmarshaler(&descopts.Field, rawOptions) } func (xd *Extension) unmarshalOptions(b []byte) { for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.VarintType: v, m := protowire.ConsumeVarint(b) b = b[m:] switch num { case fieldnum.FieldOptions_Packed: xd.L2.IsPacked = protowire.DecodeBool(v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } } func (sd *Service) unmarshalFull(b []byte, sb *strs.Builder) { var rawMethods [][]byte var rawOptions []byte sd.L2 = new(ServiceL2) for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.BytesType: v, m := protowire.ConsumeBytes(b) b = b[m:] switch num { case fieldnum.ServiceDescriptorProto_Method: rawMethods = append(rawMethods, v) case fieldnum.ServiceDescriptorProto_Options: rawOptions = appendOptions(rawOptions, v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } if len(rawMethods) > 0 { sd.L2.Methods.List = make([]Method, len(rawMethods)) for i, b := range rawMethods { sd.L2.Methods.List[i].unmarshalFull(b, sb, sd.L0.ParentFile, sd, i) } } sd.L2.Options = sd.L0.ParentFile.builder.optionsUnmarshaler(&descopts.Service, rawOptions) } func (md *Method) unmarshalFull(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) { md.L0.ParentFile = pf md.L0.Parent = pd md.L0.Index = i var rawOptions []byte for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) b = b[n:] switch typ { case protowire.VarintType: v, m := protowire.ConsumeVarint(b) b = b[m:] switch num { case fieldnum.MethodDescriptorProto_ClientStreaming: md.L1.IsStreamingClient = protowire.DecodeBool(v) case fieldnum.MethodDescriptorProto_ServerStreaming: md.L1.IsStreamingServer = protowire.DecodeBool(v) } case protowire.BytesType: v, m := protowire.ConsumeBytes(b) b = b[m:] switch num { case fieldnum.MethodDescriptorProto_Name: md.L0.FullName = appendFullName(sb, pd.FullName(), v) case fieldnum.MethodDescriptorProto_InputType: md.L1.Input = PlaceholderMessage(makeFullName(sb, v)) case fieldnum.MethodDescriptorProto_OutputType: md.L1.Output = PlaceholderMessage(makeFullName(sb, v)) case fieldnum.MethodDescriptorProto_Options: rawOptions = appendOptions(rawOptions, v) } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] } } md.L1.Options = pf.builder.optionsUnmarshaler(&descopts.Method, rawOptions) } // appendOptions appends src to dst, where the returned slice is never nil. // This is necessary to distinguish between empty and unpopulated options. func appendOptions(dst, src []byte) []byte { if dst == nil { dst = []byte{} } return append(dst, src...) } // optionsUnmarshaler constructs a lazy unmarshal function for an options message. // // The type of message to unmarshal to is passed as a pointer since the // vars in descopts may not yet be populated at the time this function is called. func (db *Builder) optionsUnmarshaler(p *pref.ProtoMessage, b []byte) func() pref.ProtoMessage { if b == nil { return nil } var opts pref.ProtoMessage var once sync.Once return func() pref.ProtoMessage { once.Do(func() { if *p == nil { panic("Descriptor.Options called without importing the descriptor package") } opts = reflect.New(reflect.TypeOf(*p).Elem()).Interface().(pref.ProtoMessage) if err := (proto.UnmarshalOptions{ AllowPartial: true, Resolver: db.TypeResolver, }).Unmarshal(b, opts); err != nil { panic(err) } }) return opts } }