vendor/google.golang.org/protobuf/encoding/prototext/encode.go
changeset 256 6d9efbef00a9
child 260 445e01aede7e
equal deleted inserted replaced
255:4f153a23adab 256:6d9efbef00a9
       
     1 // Copyright 2018 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 prototext
       
     6 
       
     7 import (
       
     8 	"fmt"
       
     9 	"strconv"
       
    10 	"unicode/utf8"
       
    11 
       
    12 	"google.golang.org/protobuf/encoding/protowire"
       
    13 	"google.golang.org/protobuf/internal/encoding/messageset"
       
    14 	"google.golang.org/protobuf/internal/encoding/text"
       
    15 	"google.golang.org/protobuf/internal/errors"
       
    16 	"google.golang.org/protobuf/internal/flags"
       
    17 	"google.golang.org/protobuf/internal/genid"
       
    18 	"google.golang.org/protobuf/internal/order"
       
    19 	"google.golang.org/protobuf/internal/pragma"
       
    20 	"google.golang.org/protobuf/internal/strs"
       
    21 	"google.golang.org/protobuf/proto"
       
    22 	"google.golang.org/protobuf/reflect/protoreflect"
       
    23 	pref "google.golang.org/protobuf/reflect/protoreflect"
       
    24 	"google.golang.org/protobuf/reflect/protoregistry"
       
    25 )
       
    26 
       
    27 const defaultIndent = "  "
       
    28 
       
    29 // Format formats the message as a multiline string.
       
    30 // This function is only intended for human consumption and ignores errors.
       
    31 // Do not depend on the output being stable. It may change over time across
       
    32 // different versions of the program.
       
    33 func Format(m proto.Message) string {
       
    34 	return MarshalOptions{Multiline: true}.Format(m)
       
    35 }
       
    36 
       
    37 // Marshal writes the given proto.Message in textproto format using default
       
    38 // options. Do not depend on the output being stable. It may change over time
       
    39 // across different versions of the program.
       
    40 func Marshal(m proto.Message) ([]byte, error) {
       
    41 	return MarshalOptions{}.Marshal(m)
       
    42 }
       
    43 
       
    44 // MarshalOptions is a configurable text format marshaler.
       
    45 type MarshalOptions struct {
       
    46 	pragma.NoUnkeyedLiterals
       
    47 
       
    48 	// Multiline specifies whether the marshaler should format the output in
       
    49 	// indented-form with every textual element on a new line.
       
    50 	// If Indent is an empty string, then an arbitrary indent is chosen.
       
    51 	Multiline bool
       
    52 
       
    53 	// Indent specifies the set of indentation characters to use in a multiline
       
    54 	// formatted output such that every entry is preceded by Indent and
       
    55 	// terminated by a newline. If non-empty, then Multiline is treated as true.
       
    56 	// Indent can only be composed of space or tab characters.
       
    57 	Indent string
       
    58 
       
    59 	// EmitASCII specifies whether to format strings and bytes as ASCII only
       
    60 	// as opposed to using UTF-8 encoding when possible.
       
    61 	EmitASCII bool
       
    62 
       
    63 	// allowInvalidUTF8 specifies whether to permit the encoding of strings
       
    64 	// with invalid UTF-8. This is unexported as it is intended to only
       
    65 	// be specified by the Format method.
       
    66 	allowInvalidUTF8 bool
       
    67 
       
    68 	// AllowPartial allows messages that have missing required fields to marshal
       
    69 	// without returning an error. If AllowPartial is false (the default),
       
    70 	// Marshal will return error if there are any missing required fields.
       
    71 	AllowPartial bool
       
    72 
       
    73 	// EmitUnknown specifies whether to emit unknown fields in the output.
       
    74 	// If specified, the unmarshaler may be unable to parse the output.
       
    75 	// The default is to exclude unknown fields.
       
    76 	EmitUnknown bool
       
    77 
       
    78 	// Resolver is used for looking up types when expanding google.protobuf.Any
       
    79 	// messages. If nil, this defaults to using protoregistry.GlobalTypes.
       
    80 	Resolver interface {
       
    81 		protoregistry.ExtensionTypeResolver
       
    82 		protoregistry.MessageTypeResolver
       
    83 	}
       
    84 }
       
    85 
       
    86 // Format formats the message as a string.
       
    87 // This method is only intended for human consumption and ignores errors.
       
    88 // Do not depend on the output being stable. It may change over time across
       
    89 // different versions of the program.
       
    90 func (o MarshalOptions) Format(m proto.Message) string {
       
    91 	if m == nil || !m.ProtoReflect().IsValid() {
       
    92 		return "<nil>" // invalid syntax, but okay since this is for debugging
       
    93 	}
       
    94 	o.allowInvalidUTF8 = true
       
    95 	o.AllowPartial = true
       
    96 	o.EmitUnknown = true
       
    97 	b, _ := o.Marshal(m)
       
    98 	return string(b)
       
    99 }
       
   100 
       
   101 // Marshal writes the given proto.Message in textproto format using options in
       
   102 // MarshalOptions object. Do not depend on the output being stable. It may
       
   103 // change over time across different versions of the program.
       
   104 func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
       
   105 	return o.marshal(m)
       
   106 }
       
   107 
       
   108 // marshal is a centralized function that all marshal operations go through.
       
   109 // For profiling purposes, avoid changing the name of this function or
       
   110 // introducing other code paths for marshal that do not go through this.
       
   111 func (o MarshalOptions) marshal(m proto.Message) ([]byte, error) {
       
   112 	var delims = [2]byte{'{', '}'}
       
   113 
       
   114 	if o.Multiline && o.Indent == "" {
       
   115 		o.Indent = defaultIndent
       
   116 	}
       
   117 	if o.Resolver == nil {
       
   118 		o.Resolver = protoregistry.GlobalTypes
       
   119 	}
       
   120 
       
   121 	internalEnc, err := text.NewEncoder(o.Indent, delims, o.EmitASCII)
       
   122 	if err != nil {
       
   123 		return nil, err
       
   124 	}
       
   125 
       
   126 	// Treat nil message interface as an empty message,
       
   127 	// in which case there is nothing to output.
       
   128 	if m == nil {
       
   129 		return []byte{}, nil
       
   130 	}
       
   131 
       
   132 	enc := encoder{internalEnc, o}
       
   133 	err = enc.marshalMessage(m.ProtoReflect(), false)
       
   134 	if err != nil {
       
   135 		return nil, err
       
   136 	}
       
   137 	out := enc.Bytes()
       
   138 	if len(o.Indent) > 0 && len(out) > 0 {
       
   139 		out = append(out, '\n')
       
   140 	}
       
   141 	if o.AllowPartial {
       
   142 		return out, nil
       
   143 	}
       
   144 	return out, proto.CheckInitialized(m)
       
   145 }
       
   146 
       
   147 type encoder struct {
       
   148 	*text.Encoder
       
   149 	opts MarshalOptions
       
   150 }
       
   151 
       
   152 // marshalMessage marshals the given protoreflect.Message.
       
   153 func (e encoder) marshalMessage(m pref.Message, inclDelims bool) error {
       
   154 	messageDesc := m.Descriptor()
       
   155 	if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
       
   156 		return errors.New("no support for proto1 MessageSets")
       
   157 	}
       
   158 
       
   159 	if inclDelims {
       
   160 		e.StartMessage()
       
   161 		defer e.EndMessage()
       
   162 	}
       
   163 
       
   164 	// Handle Any expansion.
       
   165 	if messageDesc.FullName() == genid.Any_message_fullname {
       
   166 		if e.marshalAny(m) {
       
   167 			return nil
       
   168 		}
       
   169 		// If unable to expand, continue on to marshal Any as a regular message.
       
   170 	}
       
   171 
       
   172 	// Marshal fields.
       
   173 	var err error
       
   174 	order.RangeFields(m, order.IndexNameFieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
       
   175 		if err = e.marshalField(fd.TextName(), v, fd); err != nil {
       
   176 			return false
       
   177 		}
       
   178 		return true
       
   179 	})
       
   180 	if err != nil {
       
   181 		return err
       
   182 	}
       
   183 
       
   184 	// Marshal unknown fields.
       
   185 	if e.opts.EmitUnknown {
       
   186 		e.marshalUnknown(m.GetUnknown())
       
   187 	}
       
   188 
       
   189 	return nil
       
   190 }
       
   191 
       
   192 // marshalField marshals the given field with protoreflect.Value.
       
   193 func (e encoder) marshalField(name string, val pref.Value, fd pref.FieldDescriptor) error {
       
   194 	switch {
       
   195 	case fd.IsList():
       
   196 		return e.marshalList(name, val.List(), fd)
       
   197 	case fd.IsMap():
       
   198 		return e.marshalMap(name, val.Map(), fd)
       
   199 	default:
       
   200 		e.WriteName(name)
       
   201 		return e.marshalSingular(val, fd)
       
   202 	}
       
   203 }
       
   204 
       
   205 // marshalSingular marshals the given non-repeated field value. This includes
       
   206 // all scalar types, enums, messages, and groups.
       
   207 func (e encoder) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
       
   208 	kind := fd.Kind()
       
   209 	switch kind {
       
   210 	case pref.BoolKind:
       
   211 		e.WriteBool(val.Bool())
       
   212 
       
   213 	case pref.StringKind:
       
   214 		s := val.String()
       
   215 		if !e.opts.allowInvalidUTF8 && strs.EnforceUTF8(fd) && !utf8.ValidString(s) {
       
   216 			return errors.InvalidUTF8(string(fd.FullName()))
       
   217 		}
       
   218 		e.WriteString(s)
       
   219 
       
   220 	case pref.Int32Kind, pref.Int64Kind,
       
   221 		pref.Sint32Kind, pref.Sint64Kind,
       
   222 		pref.Sfixed32Kind, pref.Sfixed64Kind:
       
   223 		e.WriteInt(val.Int())
       
   224 
       
   225 	case pref.Uint32Kind, pref.Uint64Kind,
       
   226 		pref.Fixed32Kind, pref.Fixed64Kind:
       
   227 		e.WriteUint(val.Uint())
       
   228 
       
   229 	case pref.FloatKind:
       
   230 		// Encoder.WriteFloat handles the special numbers NaN and infinites.
       
   231 		e.WriteFloat(val.Float(), 32)
       
   232 
       
   233 	case pref.DoubleKind:
       
   234 		// Encoder.WriteFloat handles the special numbers NaN and infinites.
       
   235 		e.WriteFloat(val.Float(), 64)
       
   236 
       
   237 	case pref.BytesKind:
       
   238 		e.WriteString(string(val.Bytes()))
       
   239 
       
   240 	case pref.EnumKind:
       
   241 		num := val.Enum()
       
   242 		if desc := fd.Enum().Values().ByNumber(num); desc != nil {
       
   243 			e.WriteLiteral(string(desc.Name()))
       
   244 		} else {
       
   245 			// Use numeric value if there is no enum description.
       
   246 			e.WriteInt(int64(num))
       
   247 		}
       
   248 
       
   249 	case pref.MessageKind, pref.GroupKind:
       
   250 		return e.marshalMessage(val.Message(), true)
       
   251 
       
   252 	default:
       
   253 		panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
       
   254 	}
       
   255 	return nil
       
   256 }
       
   257 
       
   258 // marshalList marshals the given protoreflect.List as multiple name-value fields.
       
   259 func (e encoder) marshalList(name string, list pref.List, fd pref.FieldDescriptor) error {
       
   260 	size := list.Len()
       
   261 	for i := 0; i < size; i++ {
       
   262 		e.WriteName(name)
       
   263 		if err := e.marshalSingular(list.Get(i), fd); err != nil {
       
   264 			return err
       
   265 		}
       
   266 	}
       
   267 	return nil
       
   268 }
       
   269 
       
   270 // marshalMap marshals the given protoreflect.Map as multiple name-value fields.
       
   271 func (e encoder) marshalMap(name string, mmap pref.Map, fd pref.FieldDescriptor) error {
       
   272 	var err error
       
   273 	order.RangeEntries(mmap, order.GenericKeyOrder, func(key pref.MapKey, val pref.Value) bool {
       
   274 		e.WriteName(name)
       
   275 		e.StartMessage()
       
   276 		defer e.EndMessage()
       
   277 
       
   278 		e.WriteName(string(genid.MapEntry_Key_field_name))
       
   279 		err = e.marshalSingular(key.Value(), fd.MapKey())
       
   280 		if err != nil {
       
   281 			return false
       
   282 		}
       
   283 
       
   284 		e.WriteName(string(genid.MapEntry_Value_field_name))
       
   285 		err = e.marshalSingular(val, fd.MapValue())
       
   286 		if err != nil {
       
   287 			return false
       
   288 		}
       
   289 		return true
       
   290 	})
       
   291 	return err
       
   292 }
       
   293 
       
   294 // marshalUnknown parses the given []byte and marshals fields out.
       
   295 // This function assumes proper encoding in the given []byte.
       
   296 func (e encoder) marshalUnknown(b []byte) {
       
   297 	const dec = 10
       
   298 	const hex = 16
       
   299 	for len(b) > 0 {
       
   300 		num, wtype, n := protowire.ConsumeTag(b)
       
   301 		b = b[n:]
       
   302 		e.WriteName(strconv.FormatInt(int64(num), dec))
       
   303 
       
   304 		switch wtype {
       
   305 		case protowire.VarintType:
       
   306 			var v uint64
       
   307 			v, n = protowire.ConsumeVarint(b)
       
   308 			e.WriteUint(v)
       
   309 		case protowire.Fixed32Type:
       
   310 			var v uint32
       
   311 			v, n = protowire.ConsumeFixed32(b)
       
   312 			e.WriteLiteral("0x" + strconv.FormatUint(uint64(v), hex))
       
   313 		case protowire.Fixed64Type:
       
   314 			var v uint64
       
   315 			v, n = protowire.ConsumeFixed64(b)
       
   316 			e.WriteLiteral("0x" + strconv.FormatUint(v, hex))
       
   317 		case protowire.BytesType:
       
   318 			var v []byte
       
   319 			v, n = protowire.ConsumeBytes(b)
       
   320 			e.WriteString(string(v))
       
   321 		case protowire.StartGroupType:
       
   322 			e.StartMessage()
       
   323 			var v []byte
       
   324 			v, n = protowire.ConsumeGroup(num, b)
       
   325 			e.marshalUnknown(v)
       
   326 			e.EndMessage()
       
   327 		default:
       
   328 			panic(fmt.Sprintf("prototext: error parsing unknown field wire type: %v", wtype))
       
   329 		}
       
   330 
       
   331 		b = b[n:]
       
   332 	}
       
   333 }
       
   334 
       
   335 // marshalAny marshals the given google.protobuf.Any message in expanded form.
       
   336 // It returns true if it was able to marshal, else false.
       
   337 func (e encoder) marshalAny(any pref.Message) bool {
       
   338 	// Construct the embedded message.
       
   339 	fds := any.Descriptor().Fields()
       
   340 	fdType := fds.ByNumber(genid.Any_TypeUrl_field_number)
       
   341 	typeURL := any.Get(fdType).String()
       
   342 	mt, err := e.opts.Resolver.FindMessageByURL(typeURL)
       
   343 	if err != nil {
       
   344 		return false
       
   345 	}
       
   346 	m := mt.New().Interface()
       
   347 
       
   348 	// Unmarshal bytes into embedded message.
       
   349 	fdValue := fds.ByNumber(genid.Any_Value_field_number)
       
   350 	value := any.Get(fdValue)
       
   351 	err = proto.UnmarshalOptions{
       
   352 		AllowPartial: true,
       
   353 		Resolver:     e.opts.Resolver,
       
   354 	}.Unmarshal(value.Bytes(), m)
       
   355 	if err != nil {
       
   356 		return false
       
   357 	}
       
   358 
       
   359 	// Get current encoder position. If marshaling fails, reset encoder output
       
   360 	// back to this position.
       
   361 	pos := e.Snapshot()
       
   362 
       
   363 	// Field name is the proto field name enclosed in [].
       
   364 	e.WriteName("[" + typeURL + "]")
       
   365 	err = e.marshalMessage(m.ProtoReflect(), true)
       
   366 	if err != nil {
       
   367 		e.Reset(pos)
       
   368 		return false
       
   369 	}
       
   370 	return true
       
   371 }