You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
10 KiB
390 lines
10 KiB
// Protocol Buffers for Go with Gadgets |
|
// |
|
// Copyright (c) 2013, The GoGo Authors. All rights reserved. |
|
// http://github.com/gogo/protobuf |
|
// |
|
// Redistribution and use in source and binary forms, with or without |
|
// modification, are permitted provided that the following conditions are |
|
// met: |
|
// |
|
// * Redistributions of source code must retain the above copyright |
|
// notice, this list of conditions and the following disclaimer. |
|
// * Redistributions in binary form must reproduce the above |
|
// copyright notice, this list of conditions and the following disclaimer |
|
// in the documentation and/or other materials provided with the |
|
// distribution. |
|
// |
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
|
|
package descriptor |
|
|
|
import ( |
|
"strings" |
|
) |
|
|
|
func (msg *DescriptorProto) GetMapFields() (*FieldDescriptorProto, *FieldDescriptorProto) { |
|
if !msg.GetOptions().GetMapEntry() { |
|
return nil, nil |
|
} |
|
return msg.GetField()[0], msg.GetField()[1] |
|
} |
|
|
|
func dotToUnderscore(r rune) rune { |
|
if r == '.' { |
|
return '_' |
|
} |
|
return r |
|
} |
|
|
|
func (field *FieldDescriptorProto) WireType() (wire int) { |
|
switch *field.Type { |
|
case FieldDescriptorProto_TYPE_DOUBLE: |
|
return 1 |
|
case FieldDescriptorProto_TYPE_FLOAT: |
|
return 5 |
|
case FieldDescriptorProto_TYPE_INT64: |
|
return 0 |
|
case FieldDescriptorProto_TYPE_UINT64: |
|
return 0 |
|
case FieldDescriptorProto_TYPE_INT32: |
|
return 0 |
|
case FieldDescriptorProto_TYPE_UINT32: |
|
return 0 |
|
case FieldDescriptorProto_TYPE_FIXED64: |
|
return 1 |
|
case FieldDescriptorProto_TYPE_FIXED32: |
|
return 5 |
|
case FieldDescriptorProto_TYPE_BOOL: |
|
return 0 |
|
case FieldDescriptorProto_TYPE_STRING: |
|
return 2 |
|
case FieldDescriptorProto_TYPE_GROUP: |
|
return 2 |
|
case FieldDescriptorProto_TYPE_MESSAGE: |
|
return 2 |
|
case FieldDescriptorProto_TYPE_BYTES: |
|
return 2 |
|
case FieldDescriptorProto_TYPE_ENUM: |
|
return 0 |
|
case FieldDescriptorProto_TYPE_SFIXED32: |
|
return 5 |
|
case FieldDescriptorProto_TYPE_SFIXED64: |
|
return 1 |
|
case FieldDescriptorProto_TYPE_SINT32: |
|
return 0 |
|
case FieldDescriptorProto_TYPE_SINT64: |
|
return 0 |
|
} |
|
panic("unreachable") |
|
} |
|
|
|
func (field *FieldDescriptorProto) GetKeyUint64() (x uint64) { |
|
packed := field.IsPacked() |
|
wireType := field.WireType() |
|
fieldNumber := field.GetNumber() |
|
if packed { |
|
wireType = 2 |
|
} |
|
x = uint64(uint32(fieldNumber)<<3 | uint32(wireType)) |
|
return x |
|
} |
|
|
|
func (field *FieldDescriptorProto) GetKey3Uint64() (x uint64) { |
|
packed := field.IsPacked3() |
|
wireType := field.WireType() |
|
fieldNumber := field.GetNumber() |
|
if packed { |
|
wireType = 2 |
|
} |
|
x = uint64(uint32(fieldNumber)<<3 | uint32(wireType)) |
|
return x |
|
} |
|
|
|
func (field *FieldDescriptorProto) GetKey() []byte { |
|
x := field.GetKeyUint64() |
|
i := 0 |
|
keybuf := make([]byte, 0) |
|
for i = 0; x > 127; i++ { |
|
keybuf = append(keybuf, 0x80|uint8(x&0x7F)) |
|
x >>= 7 |
|
} |
|
keybuf = append(keybuf, uint8(x)) |
|
return keybuf |
|
} |
|
|
|
func (field *FieldDescriptorProto) GetKey3() []byte { |
|
x := field.GetKey3Uint64() |
|
i := 0 |
|
keybuf := make([]byte, 0) |
|
for i = 0; x > 127; i++ { |
|
keybuf = append(keybuf, 0x80|uint8(x&0x7F)) |
|
x >>= 7 |
|
} |
|
keybuf = append(keybuf, uint8(x)) |
|
return keybuf |
|
} |
|
|
|
func (desc *FileDescriptorSet) GetField(packageName, messageName, fieldName string) *FieldDescriptorProto { |
|
msg := desc.GetMessage(packageName, messageName) |
|
if msg == nil { |
|
return nil |
|
} |
|
for _, field := range msg.GetField() { |
|
if field.GetName() == fieldName { |
|
return field |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
func (file *FileDescriptorProto) GetMessage(typeName string) *DescriptorProto { |
|
for _, msg := range file.GetMessageType() { |
|
if msg.GetName() == typeName { |
|
return msg |
|
} |
|
nes := file.GetNestedMessage(msg, strings.TrimPrefix(typeName, msg.GetName()+".")) |
|
if nes != nil { |
|
return nes |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
func (file *FileDescriptorProto) GetNestedMessage(msg *DescriptorProto, typeName string) *DescriptorProto { |
|
for _, nes := range msg.GetNestedType() { |
|
if nes.GetName() == typeName { |
|
return nes |
|
} |
|
res := file.GetNestedMessage(nes, strings.TrimPrefix(typeName, nes.GetName()+".")) |
|
if res != nil { |
|
return res |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
func (desc *FileDescriptorSet) GetMessage(packageName string, typeName string) *DescriptorProto { |
|
for _, file := range desc.GetFile() { |
|
if strings.Map(dotToUnderscore, file.GetPackage()) != strings.Map(dotToUnderscore, packageName) { |
|
continue |
|
} |
|
for _, msg := range file.GetMessageType() { |
|
if msg.GetName() == typeName { |
|
return msg |
|
} |
|
} |
|
for _, msg := range file.GetMessageType() { |
|
for _, nes := range msg.GetNestedType() { |
|
if nes.GetName() == typeName { |
|
return nes |
|
} |
|
if msg.GetName()+"."+nes.GetName() == typeName { |
|
return nes |
|
} |
|
} |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
func (desc *FileDescriptorSet) IsProto3(packageName string, typeName string) bool { |
|
for _, file := range desc.GetFile() { |
|
if strings.Map(dotToUnderscore, file.GetPackage()) != strings.Map(dotToUnderscore, packageName) { |
|
continue |
|
} |
|
for _, msg := range file.GetMessageType() { |
|
if msg.GetName() == typeName { |
|
return file.GetSyntax() == "proto3" |
|
} |
|
} |
|
for _, msg := range file.GetMessageType() { |
|
for _, nes := range msg.GetNestedType() { |
|
if nes.GetName() == typeName { |
|
return file.GetSyntax() == "proto3" |
|
} |
|
if msg.GetName()+"."+nes.GetName() == typeName { |
|
return file.GetSyntax() == "proto3" |
|
} |
|
} |
|
} |
|
} |
|
return false |
|
} |
|
|
|
func (msg *DescriptorProto) IsExtendable() bool { |
|
return len(msg.GetExtensionRange()) > 0 |
|
} |
|
|
|
func (desc *FileDescriptorSet) FindExtension(packageName string, typeName string, fieldName string) (extPackageName string, field *FieldDescriptorProto) { |
|
parent := desc.GetMessage(packageName, typeName) |
|
if parent == nil { |
|
return "", nil |
|
} |
|
if !parent.IsExtendable() { |
|
return "", nil |
|
} |
|
extendee := "." + packageName + "." + typeName |
|
for _, file := range desc.GetFile() { |
|
for _, ext := range file.GetExtension() { |
|
if strings.Map(dotToUnderscore, file.GetPackage()) == strings.Map(dotToUnderscore, packageName) { |
|
if !(ext.GetExtendee() == typeName || ext.GetExtendee() == extendee) { |
|
continue |
|
} |
|
} else { |
|
if ext.GetExtendee() != extendee { |
|
continue |
|
} |
|
} |
|
if ext.GetName() == fieldName { |
|
return file.GetPackage(), ext |
|
} |
|
} |
|
} |
|
return "", nil |
|
} |
|
|
|
func (desc *FileDescriptorSet) FindExtensionByFieldNumber(packageName string, typeName string, fieldNum int32) (extPackageName string, field *FieldDescriptorProto) { |
|
parent := desc.GetMessage(packageName, typeName) |
|
if parent == nil { |
|
return "", nil |
|
} |
|
if !parent.IsExtendable() { |
|
return "", nil |
|
} |
|
extendee := "." + packageName + "." + typeName |
|
for _, file := range desc.GetFile() { |
|
for _, ext := range file.GetExtension() { |
|
if strings.Map(dotToUnderscore, file.GetPackage()) == strings.Map(dotToUnderscore, packageName) { |
|
if !(ext.GetExtendee() == typeName || ext.GetExtendee() == extendee) { |
|
continue |
|
} |
|
} else { |
|
if ext.GetExtendee() != extendee { |
|
continue |
|
} |
|
} |
|
if ext.GetNumber() == fieldNum { |
|
return file.GetPackage(), ext |
|
} |
|
} |
|
} |
|
return "", nil |
|
} |
|
|
|
func (desc *FileDescriptorSet) FindMessage(packageName string, typeName string, fieldName string) (msgPackageName string, msgName string) { |
|
parent := desc.GetMessage(packageName, typeName) |
|
if parent == nil { |
|
return "", "" |
|
} |
|
field := parent.GetFieldDescriptor(fieldName) |
|
if field == nil { |
|
var extPackageName string |
|
extPackageName, field = desc.FindExtension(packageName, typeName, fieldName) |
|
if field == nil { |
|
return "", "" |
|
} |
|
packageName = extPackageName |
|
} |
|
typeNames := strings.Split(field.GetTypeName(), ".") |
|
if len(typeNames) == 1 { |
|
msg := desc.GetMessage(packageName, typeName) |
|
if msg == nil { |
|
return "", "" |
|
} |
|
return packageName, msg.GetName() |
|
} |
|
if len(typeNames) > 2 { |
|
for i := 1; i < len(typeNames)-1; i++ { |
|
packageName = strings.Join(typeNames[1:len(typeNames)-i], ".") |
|
typeName = strings.Join(typeNames[len(typeNames)-i:], ".") |
|
msg := desc.GetMessage(packageName, typeName) |
|
if msg != nil { |
|
typeNames := strings.Split(msg.GetName(), ".") |
|
if len(typeNames) == 1 { |
|
return packageName, msg.GetName() |
|
} |
|
return strings.Join(typeNames[1:len(typeNames)-1], "."), typeNames[len(typeNames)-1] |
|
} |
|
} |
|
} |
|
return "", "" |
|
} |
|
|
|
func (msg *DescriptorProto) GetFieldDescriptor(fieldName string) *FieldDescriptorProto { |
|
for _, field := range msg.GetField() { |
|
if field.GetName() == fieldName { |
|
return field |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
func (desc *FileDescriptorSet) GetEnum(packageName string, typeName string) *EnumDescriptorProto { |
|
for _, file := range desc.GetFile() { |
|
if strings.Map(dotToUnderscore, file.GetPackage()) != strings.Map(dotToUnderscore, packageName) { |
|
continue |
|
} |
|
for _, enum := range file.GetEnumType() { |
|
if enum.GetName() == typeName { |
|
return enum |
|
} |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
func (f *FieldDescriptorProto) IsEnum() bool { |
|
return *f.Type == FieldDescriptorProto_TYPE_ENUM |
|
} |
|
|
|
func (f *FieldDescriptorProto) IsMessage() bool { |
|
return *f.Type == FieldDescriptorProto_TYPE_MESSAGE |
|
} |
|
|
|
func (f *FieldDescriptorProto) IsBytes() bool { |
|
return *f.Type == FieldDescriptorProto_TYPE_BYTES |
|
} |
|
|
|
func (f *FieldDescriptorProto) IsRepeated() bool { |
|
return f.Label != nil && *f.Label == FieldDescriptorProto_LABEL_REPEATED |
|
} |
|
|
|
func (f *FieldDescriptorProto) IsString() bool { |
|
return *f.Type == FieldDescriptorProto_TYPE_STRING |
|
} |
|
|
|
func (f *FieldDescriptorProto) IsBool() bool { |
|
return *f.Type == FieldDescriptorProto_TYPE_BOOL |
|
} |
|
|
|
func (f *FieldDescriptorProto) IsRequired() bool { |
|
return f.Label != nil && *f.Label == FieldDescriptorProto_LABEL_REQUIRED |
|
} |
|
|
|
func (f *FieldDescriptorProto) IsPacked() bool { |
|
return f.Options != nil && f.GetOptions().GetPacked() |
|
} |
|
|
|
func (f *FieldDescriptorProto) IsPacked3() bool { |
|
if f.IsRepeated() && f.IsScalar() { |
|
if f.Options == nil || f.GetOptions().Packed == nil { |
|
return true |
|
} |
|
return f.Options != nil && f.GetOptions().GetPacked() |
|
} |
|
return false |
|
} |
|
|
|
func (m *DescriptorProto) HasExtension() bool { |
|
return len(m.ExtensionRange) > 0 |
|
}
|
|
|