gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }