func getFieldNumber(descriptorSet *descriptor.FileDescriptorSet, rootPkg string, rootMsg string, msg *descriptor.DescriptorProto, fieldNum int32) *descriptor.FieldDescriptorProto { for _, f := range msg.GetField() { if f.GetNumber() == fieldNum { return f } } if !msg.IsExtendable() { return nil } extendee := "." + rootPkg + "." + rootMsg for _, file := range descriptorSet.GetFile() { for _, ext := range file.GetExtension() { if strings.Map(dotToUnderscore, file.GetPackage()) == strings.Map(dotToUnderscore, rootPkg) { if !(ext.GetExtendee() == rootMsg || ext.GetExtendee() == extendee) { continue } } else { if ext.GetExtendee() != extendee { continue } } if ext.GetNumber() == fieldNum { return ext } } } return nil }
// The NoMerge function checks that the marshaled protocol buffer does not require any merging when unmarshaling. // When this property holds, streaming processing is possible. // // See below quotes from the protocol buffer documentation that describes how merging should work. // // https://developers.google.com/protocol-buffers/docs/encoding#optional // // Normally, an encoded message would never have more than one instance of an optional or required field. // However, parsers are expected to handle the case in which they do. // For numeric types and strings, if the same value appears multiple times, the parser accepts the last value it sees. // For embedded message fields, the parser merges multiple instances of the same field, // as if with the Message::MergeFrom method – that is, // all singular scalar fields in the latter instance replace those in the former, // singular embedded messages are merged, and repeated fields are concatenated. // The effect of these rules is that parsing the concatenation of two encoded messages produces // exactly the same result as if you had parsed the two messages separately and merged the resulting objects. // That is, this: // // MyMessage message; // message.ParseFromString(str1 + str2); // // is equivalent to this: // // MyMessage message, message2; // message.ParseFromString(str1); // message2.ParseFromString(str2); // message.MergeFrom(message2); // // This property is occasionally useful, as it allows you to merge two messages even if you do not know their types. // // https://developers.google.com/protocol-buffers/docs/encoding#order // // However, protocol buffer parsers must be able to parse fields in any order, // as not all messages are created by simply serializing an object – for instance, // it's sometimes useful to merge two messages by simply concatenating them. func NoMerge(buf []byte, descriptorSet *descriptor.FileDescriptorSet, rootPkg string, rootMsg string) error { msg := descriptorSet.GetMessage(rootPkg, rootMsg) if msg == nil { return &errUndefined{rootPkg, rootMsg, ""} } i := 0 seen := make(map[int32]bool) for i < len(buf) { key, n, err := decodeVarint(buf, i) if err != nil { return err } i = i + n fieldNum := int32(key >> 3) wireType := int(key & 0x7) field := getFieldNumber(descriptorSet, rootPkg, rootMsg, msg, fieldNum) if field == nil || field.GetLabel() == descriptor.FieldDescriptorProto_LABEL_REPEATED { i, err = skip(buf, i, wireType) if err != nil { return err } continue } if seen[fieldNum] { return &errMerge{msg.GetName() + "." + field.GetName()} } seen[fieldNum] = true if !field.IsMessage() { i, err = skip(buf, i, wireType) if err != nil { return err } continue } length, n, err := decodeVarint(buf, i) if err != nil { return err } i += n fieldPkg, fieldMsg := descriptorSet.FindMessage(rootPkg, rootMsg, field.GetName()) if len(fieldMsg) == 0 { return &errUndefined{rootPkg, rootMsg, field.GetName()} } err = NoMerge(buf[i:i+int(length)], descriptorSet, fieldPkg, fieldMsg) if err != nil { return err } i += int(length) } return nil }
func new(rootPackage string, rootMessage string, descSet *descriptor.FileDescriptorSet, path string) (*fdesc, error) { fieldpaths := strings.Split(path, ".") keys := make([]uint64, len(fieldpaths)) fields := make([]*descriptor.FieldDescriptorProto, len(fieldpaths)) curPackage := rootPackage curMessage := rootMessage last := len(fieldpaths) - 1 var fieldDesc *descriptor.FieldDescriptorProto for i, f := range fieldpaths { fieldName := f fieldDesc = descSet.GetField(curPackage, curMessage, fieldName) if fieldDesc == nil { curPackage, fieldDesc = descSet.FindExtension(curPackage, curMessage, fieldName) if fieldDesc == nil { return nil, &errChild{fieldName: fieldName, pkg: curPackage, msg: curMessage} } typeNames := strings.Split(fieldDesc.GetTypeName(), ".") curMessage = fieldDesc.GetTypeName() if len(typeNames) > 1 { curPackage = typeNames[1] curMessage = typeNames[2] } fieldKey := fieldDesc.GetKeyUint64() keys[i] = fieldKey fields[i] = fieldDesc } else { fieldKey := fieldDesc.GetKeyUint64() if fieldDesc.IsMessage() { curPackage, curMessage = descSet.FindMessage(curPackage, curMessage, fieldName) } else if i != last { return nil, &errMessage{fieldName} } keys[i] = fieldKey fields[i] = fieldDesc } } fd := &fdesc{curPackage, curMessage, fields, fieldDesc, keys, 0} if fieldDesc.GetType() == descriptor.FieldDescriptorProto_TYPE_ENUM { typeNames := strings.Split(fieldDesc.GetTypeName(), ".") enumMessage := fieldDesc.GetTypeName() enumPackage := curPackage if len(typeNames) > 1 { enumPackage = typeNames[1] enumMessage = typeNames[2] } enum := descSet.GetEnum(enumPackage, enumMessage) if enum == nil { return nil, &errChild{fieldName: fieldDesc.GetName(), pkg: enumPackage, msg: enumMessage} } for _, v := range enum.GetValue() { if v.GetNumber() < fd.firstEnumValue { fd.firstEnumValue = v.GetNumber() } } } return fd, nil }
func toMessages(elems []string, fileDescriptorSet *descriptor.FileDescriptorSet, messages []string) ([]string, error) { if len(elems) < 2 { return nil, &errUndefinedMsg{elems[0], "???"} } msg := fileDescriptorSet.GetMessage(elems[0], elems[1]) if msg == nil { return nil, &errUndefinedMsg{elems[0], elems[1]} } if len(elems) == 2 { messages = append(messages, elems[0]+"."+elems[1]) return messages, nil } newPkg, newMsg := fileDescriptorSet.FindMessage(elems[0], elems[1], elems[2]) if len(newMsg) == 0 { return nil, &errUndefined{elems[0], elems[1], elems[2]} } messages = append(messages, elems[0]+"."+elems[1]) elems[1] = newPkg elems[2] = newMsg return toMessages(elems[1:], fileDescriptorSet, messages) }
//Collapses a proto fieldpath into a go fieldpath. They are different if some of the fields in the fieldpath have been embedded. func Collapse(rootPkg string, rootMsg string, path string, descriptorSet *descriptor.FileDescriptorSet) (string, error) { msg := descriptorSet.GetMessage(rootPkg, rootMsg) if msg == nil { return "", &errUndefined{rootPkg, rootMsg, path} } paths := strings.Split(path, ".") if len(paths) == 0 { return "", &errUndefined{rootPkg, rootMsg, path} } if len(paths) == 1 { return path, nil } for _, f := range msg.GetField() { if f.GetName() != paths[0] { continue } if f.IsMessage() { newRootPkg, newRootMsg := descriptorSet.FindMessage(rootPkg, rootMsg, f.GetName()) if len(newRootPkg) == 0 || len(newRootMsg) == 0 { return "", &errUndefined{rootPkg, rootMsg, path} } newPath, err := Collapse(newRootPkg, newRootMsg, strings.Join(paths[1:], "."), descriptorSet) if err != nil { return "", err } if gogoproto.IsEmbed(f) { return newPath, nil } else { return paths[0] + "." + newPath, nil } } } if msg.IsExtendable() { newRootPkg, f := descriptorSet.FindExtension(rootPkg, rootMsg, paths[0]) if f == nil { return "", &errUndefined{rootPkg, rootMsg, path} } typeName := f.GetTypeName() typeNames := strings.Split(typeName, ".") newRootMsg := typeName if len(typeNames) > 1 { newRootMsg = typeNames[len(typeNames)-1] } newPath, err := Collapse(newRootPkg, newRootMsg, strings.Join(paths[1:], "."), descriptorSet) if err != nil { return "", err } if gogoproto.IsEmbed(f) { return newPath, nil } else { return paths[0] + "." + newPath, nil } } return "", nil }
//Converts a marshalled protocol buffer to string. //It does this pretty effienctly by not combining slices. //It rather prints every element of the slice seperately. //This is typically used for debugging. func ToString(rootPkg string, rootMsg string, desc *descriptor.FileDescriptorSet, fpath string, buf []byte, tabs int, writer io.Writer) error { w := &stringWriter{tabs, writer} messagePkg := rootPkg messageName := rootMsg if len(fpath) > 0 { fd, err := new(rootPkg, rootMsg, desc, fpath) if err != nil { panic(err) } messagePkg = fd.rootPkg messageName = fd.rootMsg } msg := desc.GetMessage(messagePkg, messageName) if msg == nil { panic("message not found: " + messagePkg + "." + messageName) } offset := 0 for offset < len(buf) { key, n, err := decodeVarint(buf, offset) if err != nil { panic(err) } offset += n fieldNum := int32(key >> 3) found := false for _, f := range msg.GetField() { if f.IsPacked() { panic("not implemented") } if f.GetNumber() != fieldNum { continue } found = true if f.GetType() == descriptor.FieldDescriptorProto_TYPE_MESSAGE { length, nn, err := decodeVarint(buf, offset) if err != nil { panic(err) } offset += nn w.tab() w.String(f.GetName() + `:{` + "\n") err = ToString(messagePkg, messageName, desc, f.GetName(), buf[offset:offset+int(length)], tabs+1, writer) if err != nil { return err } offset += int(length) w.tab() w.String(`}` + "\n") break } else { w.tab() w.String(f.GetName() + `:`) var n int var err error switch f.GetType() { case descriptor.FieldDescriptorProto_TYPE_DOUBLE: n, err = DecFloat64(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_FLOAT: n, err = DecFloat32(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_INT64: n, err = DecInt64(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_UINT64: n, err = DecUint64(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_INT32: n, err = DecInt32(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_FIXED64: n, err = DecFixed64(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_FIXED32: n, err = DecFixed32(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_BOOL: n, err = DecBool(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_STRING: n, err = DecString(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_GROUP: panic("not implemented") case descriptor.FieldDescriptorProto_TYPE_BYTES: n, err = DecBytes(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_UINT32: n, err = DecUint32(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_ENUM: n, err = DecInt32(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_SFIXED32: n, err = DecSfixed32(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_SFIXED64: n, err = DecSfixed64(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_SINT32: n, err = DecSint32(buf, offset, w) case descriptor.FieldDescriptorProto_TYPE_SINT64: n, err = DecSint64(buf, offset, w) default: panic("unreachable") } offset += n if err != nil { panic(err) } w.String(",\n") break } } if !found { for _, extRange := range msg.GetExtensionRange() { if extRange.GetStart() <= fieldNum && fieldNum <= extRange.GetEnd() { found = true break } } w.tab() offset -= n nn, err := protoSkip(buf[offset:]) if err != nil { panic(err) } if !found { w.String("XXX_unrecognized:") } else { w.String("XXX_extensions:") extPkg, ext := desc.FindExtensionByFieldNumber(messagePkg, messageName, fieldNum) if ext != nil && ext.IsMessage() { names := strings.Split(ext.GetTypeName(), ".") if len(names) == 3 { _, nnn, err := decodeVarint(buf, offset+n) if err != nil { panic(err) } w.tab() w.String(extPkg + "." + names[2] + `:{` + "\n") err = ToString(extPkg, names[2], desc, "", buf[offset+n+nnn:offset+nn], tabs+1, writer) if err != nil { return err } offset += nn w.tab() w.String(`}` + "\n") break } else { panic(ext.GetTypeName()) } } } w.Bytes(buf[offset : offset+nn]) w.String("\n") offset += nn } } return nil }