text_encode.go (13043B)
1 // Copyright 2010 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 5 package proto 6 7 import ( 8 "bytes" 9 "encoding" 10 "fmt" 11 "io" 12 "math" 13 "sort" 14 "strings" 15 16 "google.golang.org/protobuf/encoding/prototext" 17 "google.golang.org/protobuf/encoding/protowire" 18 "google.golang.org/protobuf/proto" 19 "google.golang.org/protobuf/reflect/protoreflect" 20 "google.golang.org/protobuf/reflect/protoregistry" 21 ) 22 23 const wrapTextMarshalV2 = false 24 25 // TextMarshaler is a configurable text format marshaler. 26 type TextMarshaler struct { 27 Compact bool // use compact text format (one line) 28 ExpandAny bool // expand google.protobuf.Any messages of known types 29 } 30 31 // Marshal writes the proto text format of m to w. 32 func (tm *TextMarshaler) Marshal(w io.Writer, m Message) error { 33 b, err := tm.marshal(m) 34 if len(b) > 0 { 35 if _, err := w.Write(b); err != nil { 36 return err 37 } 38 } 39 return err 40 } 41 42 // Text returns a proto text formatted string of m. 43 func (tm *TextMarshaler) Text(m Message) string { 44 b, _ := tm.marshal(m) 45 return string(b) 46 } 47 48 func (tm *TextMarshaler) marshal(m Message) ([]byte, error) { 49 mr := MessageReflect(m) 50 if mr == nil || !mr.IsValid() { 51 return []byte("<nil>"), nil 52 } 53 54 if wrapTextMarshalV2 { 55 if m, ok := m.(encoding.TextMarshaler); ok { 56 return m.MarshalText() 57 } 58 59 opts := prototext.MarshalOptions{ 60 AllowPartial: true, 61 EmitUnknown: true, 62 } 63 if !tm.Compact { 64 opts.Indent = " " 65 } 66 if !tm.ExpandAny { 67 opts.Resolver = (*protoregistry.Types)(nil) 68 } 69 return opts.Marshal(mr.Interface()) 70 } else { 71 w := &textWriter{ 72 compact: tm.Compact, 73 expandAny: tm.ExpandAny, 74 complete: true, 75 } 76 77 if m, ok := m.(encoding.TextMarshaler); ok { 78 b, err := m.MarshalText() 79 if err != nil { 80 return nil, err 81 } 82 w.Write(b) 83 return w.buf, nil 84 } 85 86 err := w.writeMessage(mr) 87 return w.buf, err 88 } 89 } 90 91 var ( 92 defaultTextMarshaler = TextMarshaler{} 93 compactTextMarshaler = TextMarshaler{Compact: true} 94 ) 95 96 // MarshalText writes the proto text format of m to w. 97 func MarshalText(w io.Writer, m Message) error { return defaultTextMarshaler.Marshal(w, m) } 98 99 // MarshalTextString returns a proto text formatted string of m. 100 func MarshalTextString(m Message) string { return defaultTextMarshaler.Text(m) } 101 102 // CompactText writes the compact proto text format of m to w. 103 func CompactText(w io.Writer, m Message) error { return compactTextMarshaler.Marshal(w, m) } 104 105 // CompactTextString returns a compact proto text formatted string of m. 106 func CompactTextString(m Message) string { return compactTextMarshaler.Text(m) } 107 108 var ( 109 newline = []byte("\n") 110 endBraceNewline = []byte("}\n") 111 posInf = []byte("inf") 112 negInf = []byte("-inf") 113 nan = []byte("nan") 114 ) 115 116 // textWriter is an io.Writer that tracks its indentation level. 117 type textWriter struct { 118 compact bool // same as TextMarshaler.Compact 119 expandAny bool // same as TextMarshaler.ExpandAny 120 complete bool // whether the current position is a complete line 121 indent int // indentation level; never negative 122 buf []byte 123 } 124 125 func (w *textWriter) Write(p []byte) (n int, _ error) { 126 newlines := bytes.Count(p, newline) 127 if newlines == 0 { 128 if !w.compact && w.complete { 129 w.writeIndent() 130 } 131 w.buf = append(w.buf, p...) 132 w.complete = false 133 return len(p), nil 134 } 135 136 frags := bytes.SplitN(p, newline, newlines+1) 137 if w.compact { 138 for i, frag := range frags { 139 if i > 0 { 140 w.buf = append(w.buf, ' ') 141 n++ 142 } 143 w.buf = append(w.buf, frag...) 144 n += len(frag) 145 } 146 return n, nil 147 } 148 149 for i, frag := range frags { 150 if w.complete { 151 w.writeIndent() 152 } 153 w.buf = append(w.buf, frag...) 154 n += len(frag) 155 if i+1 < len(frags) { 156 w.buf = append(w.buf, '\n') 157 n++ 158 } 159 } 160 w.complete = len(frags[len(frags)-1]) == 0 161 return n, nil 162 } 163 164 func (w *textWriter) WriteByte(c byte) error { 165 if w.compact && c == '\n' { 166 c = ' ' 167 } 168 if !w.compact && w.complete { 169 w.writeIndent() 170 } 171 w.buf = append(w.buf, c) 172 w.complete = c == '\n' 173 return nil 174 } 175 176 func (w *textWriter) writeName(fd protoreflect.FieldDescriptor) { 177 if !w.compact && w.complete { 178 w.writeIndent() 179 } 180 w.complete = false 181 182 if fd.Kind() != protoreflect.GroupKind { 183 w.buf = append(w.buf, fd.Name()...) 184 w.WriteByte(':') 185 } else { 186 // Use message type name for group field name. 187 w.buf = append(w.buf, fd.Message().Name()...) 188 } 189 190 if !w.compact { 191 w.WriteByte(' ') 192 } 193 } 194 195 func requiresQuotes(u string) bool { 196 // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. 197 for _, ch := range u { 198 switch { 199 case ch == '.' || ch == '/' || ch == '_': 200 continue 201 case '0' <= ch && ch <= '9': 202 continue 203 case 'A' <= ch && ch <= 'Z': 204 continue 205 case 'a' <= ch && ch <= 'z': 206 continue 207 default: 208 return true 209 } 210 } 211 return false 212 } 213 214 // writeProto3Any writes an expanded google.protobuf.Any message. 215 // 216 // It returns (false, nil) if sv value can't be unmarshaled (e.g. because 217 // required messages are not linked in). 218 // 219 // It returns (true, error) when sv was written in expanded format or an error 220 // was encountered. 221 func (w *textWriter) writeProto3Any(m protoreflect.Message) (bool, error) { 222 md := m.Descriptor() 223 fdURL := md.Fields().ByName("type_url") 224 fdVal := md.Fields().ByName("value") 225 226 url := m.Get(fdURL).String() 227 mt, err := protoregistry.GlobalTypes.FindMessageByURL(url) 228 if err != nil { 229 return false, nil 230 } 231 232 b := m.Get(fdVal).Bytes() 233 m2 := mt.New() 234 if err := proto.Unmarshal(b, m2.Interface()); err != nil { 235 return false, nil 236 } 237 w.Write([]byte("[")) 238 if requiresQuotes(url) { 239 w.writeQuotedString(url) 240 } else { 241 w.Write([]byte(url)) 242 } 243 if w.compact { 244 w.Write([]byte("]:<")) 245 } else { 246 w.Write([]byte("]: <\n")) 247 w.indent++ 248 } 249 if err := w.writeMessage(m2); err != nil { 250 return true, err 251 } 252 if w.compact { 253 w.Write([]byte("> ")) 254 } else { 255 w.indent-- 256 w.Write([]byte(">\n")) 257 } 258 return true, nil 259 } 260 261 func (w *textWriter) writeMessage(m protoreflect.Message) error { 262 md := m.Descriptor() 263 if w.expandAny && md.FullName() == "google.protobuf.Any" { 264 if canExpand, err := w.writeProto3Any(m); canExpand { 265 return err 266 } 267 } 268 269 fds := md.Fields() 270 for i := 0; i < fds.Len(); { 271 fd := fds.Get(i) 272 if od := fd.ContainingOneof(); od != nil { 273 fd = m.WhichOneof(od) 274 i += od.Fields().Len() 275 } else { 276 i++ 277 } 278 if fd == nil || !m.Has(fd) { 279 continue 280 } 281 282 switch { 283 case fd.IsList(): 284 lv := m.Get(fd).List() 285 for j := 0; j < lv.Len(); j++ { 286 w.writeName(fd) 287 v := lv.Get(j) 288 if err := w.writeSingularValue(v, fd); err != nil { 289 return err 290 } 291 w.WriteByte('\n') 292 } 293 case fd.IsMap(): 294 kfd := fd.MapKey() 295 vfd := fd.MapValue() 296 mv := m.Get(fd).Map() 297 298 type entry struct{ key, val protoreflect.Value } 299 var entries []entry 300 mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { 301 entries = append(entries, entry{k.Value(), v}) 302 return true 303 }) 304 sort.Slice(entries, func(i, j int) bool { 305 switch kfd.Kind() { 306 case protoreflect.BoolKind: 307 return !entries[i].key.Bool() && entries[j].key.Bool() 308 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: 309 return entries[i].key.Int() < entries[j].key.Int() 310 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind: 311 return entries[i].key.Uint() < entries[j].key.Uint() 312 case protoreflect.StringKind: 313 return entries[i].key.String() < entries[j].key.String() 314 default: 315 panic("invalid kind") 316 } 317 }) 318 for _, entry := range entries { 319 w.writeName(fd) 320 w.WriteByte('<') 321 if !w.compact { 322 w.WriteByte('\n') 323 } 324 w.indent++ 325 w.writeName(kfd) 326 if err := w.writeSingularValue(entry.key, kfd); err != nil { 327 return err 328 } 329 w.WriteByte('\n') 330 w.writeName(vfd) 331 if err := w.writeSingularValue(entry.val, vfd); err != nil { 332 return err 333 } 334 w.WriteByte('\n') 335 w.indent-- 336 w.WriteByte('>') 337 w.WriteByte('\n') 338 } 339 default: 340 w.writeName(fd) 341 if err := w.writeSingularValue(m.Get(fd), fd); err != nil { 342 return err 343 } 344 w.WriteByte('\n') 345 } 346 } 347 348 if b := m.GetUnknown(); len(b) > 0 { 349 w.writeUnknownFields(b) 350 } 351 return w.writeExtensions(m) 352 } 353 354 func (w *textWriter) writeSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) error { 355 switch fd.Kind() { 356 case protoreflect.FloatKind, protoreflect.DoubleKind: 357 switch vf := v.Float(); { 358 case math.IsInf(vf, +1): 359 w.Write(posInf) 360 case math.IsInf(vf, -1): 361 w.Write(negInf) 362 case math.IsNaN(vf): 363 w.Write(nan) 364 default: 365 fmt.Fprint(w, v.Interface()) 366 } 367 case protoreflect.StringKind: 368 // NOTE: This does not validate UTF-8 for historical reasons. 369 w.writeQuotedString(string(v.String())) 370 case protoreflect.BytesKind: 371 w.writeQuotedString(string(v.Bytes())) 372 case protoreflect.MessageKind, protoreflect.GroupKind: 373 var bra, ket byte = '<', '>' 374 if fd.Kind() == protoreflect.GroupKind { 375 bra, ket = '{', '}' 376 } 377 w.WriteByte(bra) 378 if !w.compact { 379 w.WriteByte('\n') 380 } 381 w.indent++ 382 m := v.Message() 383 if m2, ok := m.Interface().(encoding.TextMarshaler); ok { 384 b, err := m2.MarshalText() 385 if err != nil { 386 return err 387 } 388 w.Write(b) 389 } else { 390 w.writeMessage(m) 391 } 392 w.indent-- 393 w.WriteByte(ket) 394 case protoreflect.EnumKind: 395 if ev := fd.Enum().Values().ByNumber(v.Enum()); ev != nil { 396 fmt.Fprint(w, ev.Name()) 397 } else { 398 fmt.Fprint(w, v.Enum()) 399 } 400 default: 401 fmt.Fprint(w, v.Interface()) 402 } 403 return nil 404 } 405 406 // writeQuotedString writes a quoted string in the protocol buffer text format. 407 func (w *textWriter) writeQuotedString(s string) { 408 w.WriteByte('"') 409 for i := 0; i < len(s); i++ { 410 switch c := s[i]; c { 411 case '\n': 412 w.buf = append(w.buf, `\n`...) 413 case '\r': 414 w.buf = append(w.buf, `\r`...) 415 case '\t': 416 w.buf = append(w.buf, `\t`...) 417 case '"': 418 w.buf = append(w.buf, `\"`...) 419 case '\\': 420 w.buf = append(w.buf, `\\`...) 421 default: 422 if isPrint := c >= 0x20 && c < 0x7f; isPrint { 423 w.buf = append(w.buf, c) 424 } else { 425 w.buf = append(w.buf, fmt.Sprintf(`\%03o`, c)...) 426 } 427 } 428 } 429 w.WriteByte('"') 430 } 431 432 func (w *textWriter) writeUnknownFields(b []byte) { 433 if !w.compact { 434 fmt.Fprintf(w, "/* %d unknown bytes */\n", len(b)) 435 } 436 437 for len(b) > 0 { 438 num, wtyp, n := protowire.ConsumeTag(b) 439 if n < 0 { 440 return 441 } 442 b = b[n:] 443 444 if wtyp == protowire.EndGroupType { 445 w.indent-- 446 w.Write(endBraceNewline) 447 continue 448 } 449 fmt.Fprint(w, num) 450 if wtyp != protowire.StartGroupType { 451 w.WriteByte(':') 452 } 453 if !w.compact || wtyp == protowire.StartGroupType { 454 w.WriteByte(' ') 455 } 456 switch wtyp { 457 case protowire.VarintType: 458 v, n := protowire.ConsumeVarint(b) 459 if n < 0 { 460 return 461 } 462 b = b[n:] 463 fmt.Fprint(w, v) 464 case protowire.Fixed32Type: 465 v, n := protowire.ConsumeFixed32(b) 466 if n < 0 { 467 return 468 } 469 b = b[n:] 470 fmt.Fprint(w, v) 471 case protowire.Fixed64Type: 472 v, n := protowire.ConsumeFixed64(b) 473 if n < 0 { 474 return 475 } 476 b = b[n:] 477 fmt.Fprint(w, v) 478 case protowire.BytesType: 479 v, n := protowire.ConsumeBytes(b) 480 if n < 0 { 481 return 482 } 483 b = b[n:] 484 fmt.Fprintf(w, "%q", v) 485 case protowire.StartGroupType: 486 w.WriteByte('{') 487 w.indent++ 488 default: 489 fmt.Fprintf(w, "/* unknown wire type %d */", wtyp) 490 } 491 w.WriteByte('\n') 492 } 493 } 494 495 // writeExtensions writes all the extensions in m. 496 func (w *textWriter) writeExtensions(m protoreflect.Message) error { 497 md := m.Descriptor() 498 if md.ExtensionRanges().Len() == 0 { 499 return nil 500 } 501 502 type ext struct { 503 desc protoreflect.FieldDescriptor 504 val protoreflect.Value 505 } 506 var exts []ext 507 m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { 508 if fd.IsExtension() { 509 exts = append(exts, ext{fd, v}) 510 } 511 return true 512 }) 513 sort.Slice(exts, func(i, j int) bool { 514 return exts[i].desc.Number() < exts[j].desc.Number() 515 }) 516 517 for _, ext := range exts { 518 // For message set, use the name of the message as the extension name. 519 name := string(ext.desc.FullName()) 520 if isMessageSet(ext.desc.ContainingMessage()) { 521 name = strings.TrimSuffix(name, ".message_set_extension") 522 } 523 524 if !ext.desc.IsList() { 525 if err := w.writeSingularExtension(name, ext.val, ext.desc); err != nil { 526 return err 527 } 528 } else { 529 lv := ext.val.List() 530 for i := 0; i < lv.Len(); i++ { 531 if err := w.writeSingularExtension(name, lv.Get(i), ext.desc); err != nil { 532 return err 533 } 534 } 535 } 536 } 537 return nil 538 } 539 540 func (w *textWriter) writeSingularExtension(name string, v protoreflect.Value, fd protoreflect.FieldDescriptor) error { 541 fmt.Fprintf(w, "[%s]:", name) 542 if !w.compact { 543 w.WriteByte(' ') 544 } 545 if err := w.writeSingularValue(v, fd); err != nil { 546 return err 547 } 548 w.WriteByte('\n') 549 return nil 550 } 551 552 func (w *textWriter) writeIndent() { 553 if !w.complete { 554 return 555 } 556 for i := 0; i < w.indent*2; i++ { 557 w.buf = append(w.buf, ' ') 558 } 559 w.complete = false 560 }