podman
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
5package text6
7import (8"bytes"9"fmt"10"math"11"strconv"12"strings"13
14"google.golang.org/protobuf/internal/flags"15)
16
17// Kind represents a token kind expressible in the textproto format.
18type Kind uint819
20// Kind values.
21const (22Invalid Kind = iota23EOF
24Name // Name indicates the field name.25Scalar // Scalar are scalar values, e.g. "string", 47, ENUM_LITERAL, true.26MessageOpen
27MessageClose
28ListOpen
29ListClose
30
31// comma and semi-colon are only for parsing in between values and should not be exposed.32comma
33semicolon
34
35// bof indicates beginning of file, which is the default token36// kind at the beginning of parsing.37bof = Invalid38)
39
40func (t Kind) String() string {41switch t {42case Invalid:43return "<invalid>"44case EOF:45return "eof"46case Scalar:47return "scalar"48case Name:49return "name"50case MessageOpen:51return "{"52case MessageClose:53return "}"54case ListOpen:55return "["56case ListClose:57return "]"58case comma:59return ","60case semicolon:61return ";"62default:63return fmt.Sprintf("<invalid:%v>", uint8(t))64}65}
66
67// NameKind represents different types of field names.
68type NameKind uint869
70// NameKind values.
71const (72IdentName NameKind = iota + 173TypeName
74FieldNumber
75)
76
77func (t NameKind) String() string {78switch t {79case IdentName:80return "IdentName"81case TypeName:82return "TypeName"83case FieldNumber:84return "FieldNumber"85default:86return fmt.Sprintf("<invalid:%v>", uint8(t))87}88}
89
90// Bit mask in Token.attrs to indicate if a Name token is followed by the
91// separator char ':'. The field name separator char is optional for message
92// field or repeated message field, but required for all other types. Decoder
93// simply indicates whether a Name token is followed by separator or not. It is
94// up to the prototext package to validate.
95const hasSeparator = 1 << 796
97// Scalar value types.
98const (99numberValue = iota + 1100stringValue
101literalValue
102)
103
104// Bit mask in Token.numAttrs to indicate that the number is a negative.
105const isNegative = 1 << 7106
107// Token provides a parsed token kind and value. Values are provided by the
108// different accessor methods.
109type Token struct {110// Kind of the Token object.111kind Kind
112// attrs contains metadata for the following Kinds:113// Name: hasSeparator bit and one of NameKind.114// Scalar: one of numberValue, stringValue, literalValue.115attrs uint8116// numAttrs contains metadata for numberValue:117// - highest bit is whether negative or positive.118// - lower bits indicate one of numDec, numHex, numOct, numFloat.119numAttrs uint8120// pos provides the position of the token in the original input.121pos int122// raw bytes of the serialized token.123// This is a subslice into the original input.124raw []byte125// str contains parsed string for the following:126// - stringValue of Scalar kind127// - numberValue of Scalar kind128// - TypeName of Name kind129str string130}
131
132// Kind returns the token kind.
133func (t Token) Kind() Kind {134return t.kind135}
136
137// RawString returns the read value in string.
138func (t Token) RawString() string {139return string(t.raw)140}
141
142// Pos returns the token position from the input.
143func (t Token) Pos() int {144return t.pos145}
146
147// NameKind returns IdentName, TypeName or FieldNumber.
148// It panics if type is not Name.
149func (t Token) NameKind() NameKind {150if t.kind == Name {151return NameKind(t.attrs &^ hasSeparator)152}153panic(fmt.Sprintf("Token is not a Name type: %s", t.kind))154}
155
156// HasSeparator returns true if the field name is followed by the separator char
157// ':', else false. It panics if type is not Name.
158func (t Token) HasSeparator() bool {159if t.kind == Name {160return t.attrs&hasSeparator != 0161}162panic(fmt.Sprintf("Token is not a Name type: %s", t.kind))163}
164
165// IdentName returns the value for IdentName type.
166func (t Token) IdentName() string {167if t.kind == Name && t.attrs&uint8(IdentName) != 0 {168return string(t.raw)169}170panic(fmt.Sprintf("Token is not an IdentName: %s:%s", t.kind, NameKind(t.attrs&^hasSeparator)))171}
172
173// TypeName returns the value for TypeName type.
174func (t Token) TypeName() string {175if t.kind == Name && t.attrs&uint8(TypeName) != 0 {176return t.str177}178panic(fmt.Sprintf("Token is not a TypeName: %s:%s", t.kind, NameKind(t.attrs&^hasSeparator)))179}
180
181// FieldNumber returns the value for FieldNumber type. It returns a
182// non-negative int32 value. Caller will still need to validate for the correct
183// field number range.
184func (t Token) FieldNumber() int32 {185if t.kind != Name || t.attrs&uint8(FieldNumber) == 0 {186panic(fmt.Sprintf("Token is not a FieldNumber: %s:%s", t.kind, NameKind(t.attrs&^hasSeparator)))187}188// Following should not return an error as it had already been called right189// before this Token was constructed.190num, _ := strconv.ParseInt(string(t.raw), 10, 32)191return int32(num)192}
193
194// String returns the string value for a Scalar type.
195func (t Token) String() (string, bool) {196if t.kind != Scalar || t.attrs != stringValue {197return "", false198}199return t.str, true200}
201
202// Enum returns the literal value for a Scalar type for use as enum literals.
203func (t Token) Enum() (string, bool) {204if t.kind != Scalar || t.attrs != literalValue || (len(t.raw) > 0 && t.raw[0] == '-') {205return "", false206}207return string(t.raw), true208}
209
210// Bool returns the bool value for a Scalar type.
211func (t Token) Bool() (bool, bool) {212if t.kind != Scalar {213return false, false214}215switch t.attrs {216case literalValue:217if b, ok := boolLits[string(t.raw)]; ok {218return b, true219}220case numberValue:221// Unsigned integer representation of 0 or 1 is permitted: 00, 0x0, 01,222// 0x1, etc.223n, err := strconv.ParseUint(t.str, 0, 64)224if err == nil {225switch n {226case 0:227return false, true228case 1:229return true, true230}231}232}233return false, false234}
235
236// These exact boolean literals are the ones supported in C++.
237var boolLits = map[string]bool{238"t": true,239"true": true,240"True": true,241"f": false,242"false": false,243"False": false,244}
245
246// Uint64 returns the uint64 value for a Scalar type.
247func (t Token) Uint64() (uint64, bool) {248if t.kind != Scalar || t.attrs != numberValue ||249t.numAttrs&isNegative > 0 || t.numAttrs&numFloat > 0 {250return 0, false251}252n, err := strconv.ParseUint(t.str, 0, 64)253if err != nil {254return 0, false255}256return n, true257}
258
259// Uint32 returns the uint32 value for a Scalar type.
260func (t Token) Uint32() (uint32, bool) {261if t.kind != Scalar || t.attrs != numberValue ||262t.numAttrs&isNegative > 0 || t.numAttrs&numFloat > 0 {263return 0, false264}265n, err := strconv.ParseUint(t.str, 0, 32)266if err != nil {267return 0, false268}269return uint32(n), true270}
271
272// Int64 returns the int64 value for a Scalar type.
273func (t Token) Int64() (int64, bool) {274if t.kind != Scalar || t.attrs != numberValue || t.numAttrs&numFloat > 0 {275return 0, false276}277if n, err := strconv.ParseInt(t.str, 0, 64); err == nil {278return n, true279}280// C++ accepts large positive hex numbers as negative values.281// This feature is here for proto1 backwards compatibility purposes.282if flags.ProtoLegacy && (t.numAttrs == numHex) {283if n, err := strconv.ParseUint(t.str, 0, 64); err == nil {284return int64(n), true285}286}287return 0, false288}
289
290// Int32 returns the int32 value for a Scalar type.
291func (t Token) Int32() (int32, bool) {292if t.kind != Scalar || t.attrs != numberValue || t.numAttrs&numFloat > 0 {293return 0, false294}295if n, err := strconv.ParseInt(t.str, 0, 32); err == nil {296return int32(n), true297}298// C++ accepts large positive hex numbers as negative values.299// This feature is here for proto1 backwards compatibility purposes.300if flags.ProtoLegacy && (t.numAttrs == numHex) {301if n, err := strconv.ParseUint(t.str, 0, 32); err == nil {302return int32(n), true303}304}305return 0, false306}
307
308// Float64 returns the float64 value for a Scalar type.
309func (t Token) Float64() (float64, bool) {310if t.kind != Scalar {311return 0, false312}313switch t.attrs {314case literalValue:315if f, ok := floatLits[strings.ToLower(string(t.raw))]; ok {316return f, true317}318case numberValue:319n, err := strconv.ParseFloat(t.str, 64)320if err == nil {321return n, true322}323nerr := err.(*strconv.NumError)324if nerr.Err == strconv.ErrRange {325return n, true326}327}328return 0, false329}
330
331// Float32 returns the float32 value for a Scalar type.
332func (t Token) Float32() (float32, bool) {333if t.kind != Scalar {334return 0, false335}336switch t.attrs {337case literalValue:338if f, ok := floatLits[strings.ToLower(string(t.raw))]; ok {339return float32(f), true340}341case numberValue:342n, err := strconv.ParseFloat(t.str, 64)343if err == nil {344// Overflows are treated as (-)infinity.345return float32(n), true346}347nerr := err.(*strconv.NumError)348if nerr.Err == strconv.ErrRange {349return float32(n), true350}351}352return 0, false353}
354
355// These are the supported float literals which C++ permits case-insensitive
356// variants of these.
357var floatLits = map[string]float64{358"nan": math.NaN(),359"inf": math.Inf(1),360"infinity": math.Inf(1),361"-inf": math.Inf(-1),362"-infinity": math.Inf(-1),363}
364
365// TokenEquals returns true if given Tokens are equal, else false.
366func TokenEquals(x, y Token) bool {367return x.kind == y.kind &&368x.attrs == y.attrs &&369x.numAttrs == y.numAttrs &&370x.pos == y.pos &&371bytes.Equal(x.raw, y.raw) &&372x.str == y.str373}
374